//=============================================================================
/**
 *
 *	@file		pkthln_catch.c
 *	@brief		UFOキャッチ
 *	@author		hosaka genya
 *	@data		2008.12.01
 *
 */
//=============================================================================
#include "common.h"
#include "strbuf_family.h"
#include "system/wipe.h"
#include "system/clact_tool.h"
#include "system/snd_tool.h"
#include "system/fontproc.h"
#include "gflib/touchpanel.h"

#include "../pkthln_clact.h"

#include "../../pkthln_comm_pack.h"
#include "../../pkthln_obj_common.h"
#include "../../poke_clact.h"
#include "../../poke_clact_move.h"
#include "../../pkthln_poke_act.h"
#include "../../cmn_res.h"
#include "../evt_cats.h"
#include "../event_se_def.h"
#include "../pkthln_evt_info.naix"

//成績作成用
#include "system/msgdata_util.h"
#include "msgdata/msg.naix"
#include "msgdata/msg_pokethlon.h"

#include "catch_define.h"
#include "catch_comm.h"
#include "catch_sub.h"
#include "catch_ai.h"
#include "pkthln_catch.h"


#ifdef _NITRO
		// 構造体が想定のサイズとなっているかチェック
		SDK_COMPILER_ASSERT(sizeof(CATCH_COMM_UFO) == 2);
		SDK_COMPILER_ASSERT(sizeof(CATCH_COMM_PARENT) == 36);
		SDK_COMPILER_ASSERT(sizeof(CATCH_COMM_CHILD) == 36);
#endif

#ifdef PM_DEBUG
	// 共用デバッグワーク
	extern DEBUG_PKTHLN_WORK DebugPkthlnWk;
	// UFOの移動をキー操作でフックする
//	#define DEBUG_UFO_HOOK

	#ifdef DEBUG_UFO_HOOK
		static int debug_ufo_vec = 0;
		static BOOL debug_ufo_move_trg = 0;
		static BOOL debug_ufo_visible[2] = {1,1};
	#endif
#endif

//=============================================================================
/**
 *							デバッグフラグ
 */
//=============================================================================
// PUSH情報表示フラグ
//#define DEBUG_PRINT_PUSH

//=============================================================================
/**
 *								定数定義
 */
//=============================================================================

enum
{
	POKE_L_SIZE = 64,
	POKE_S_SIZE = 32,
};

//--------------------------------------------------------------
///	UFOの状態(3 bit = 0-7)
//==============================================================
typedef enum
{
	UFO_ST_NONE = 0,
	UFO_ST_NORMAL,
	UFO_ST_DISPOUT,
	UFO_ST_POINT_1,
	UFO_ST_POINT_2,
	UFO_ST_POINT_3,
	UFO_ST_POINT_5,
} UFO_STATE;

//=============================================================================
/**
 *								構造体定義
 */
//=============================================================================
//--------------------------------------------------------------
///	コンバータから取得するパラメータ
//==============================================================
#define CATCH_CONV_PARAM_MAX (5)
typedef struct CATCH_CONV_PARAM_tag {
	int JumpDuration[ CATCH_CONV_PARAM_MAX ];
	int JumpHigh[ CATCH_CONV_PARAM_MAX ];
	int Power[ CATCH_CONV_PARAM_MAX ];	///< 相手を押す力
	int Speed[ CATCH_CONV_PARAM_MAX ];	///< 移動スピード
} CATCH_CONV_PARAM;

//--------------------------------------------------------------
///	ポケモン状態
//==============================================================
typedef enum {
	POKE_ST_NONE = 0,	///< なし
	POKE_ST_JUMP,		///< ジャンプ中
	POKE_ST_ALIVE,		///< 通常
	POKE_ST_FALL,		///< 落下
	POKE_ST_REVIVE,		///< 復活中
} POKE_STATE;

//--------------------------------------------------------------
///	ポケモン毎のパラメータ
//==============================================================
typedef struct CATCH_POKE_PARAM_tag {
	u8 JumpDuration;	///< 滞空時間
	u8 JumpHigh;		///< ジャンプの高さ
	u8 JumpLevel;		///< ジャンプのスペックレベル
	u8 DummyByte[1];
	fx32 fxPower;		///< 推進力
	fx32 fxMove;		///< 移動速度
} CATCH_POKE_PARAM;

//--------------------------------------------------------------
///	参加ポケモン管理ワーク
//==============================================================
typedef struct CATCH_POKE_tag {
	// [IN]
	PKTHLN_PTR work;
	POKE_ACT_PTR PokeActPtr;
	CATCH_POKE_PARAM* cpp; ///< CatchPokeParam
	// [PRIVATE]
	POKE_STATE State;
	VecFx32 LastPos;	///< 最終到達地点
	VecFx32 NowPos;		///< 現在地点
	VecFx32 NormDirVec;	///< 移動時に正規化された方向ベクトル(高速化のため保持)
	VecFx32 PushVec;	///< 推進ベクトル
	u32 JumpFrame : 8;		///< ジャンプ中のフレームカウンタ
	u32 JumpSendFrame : 8;	///< このフレーム中、ジャンプBITを立てる
	u32 ID : 4;				///< インデックス 0-12
	u32 Dir : 4;			///< 方向
	u32 CellType : 2;		///< セルの種類
	u32 bPush : 1;			///< 押されたフラグ
	u32 bSetPos : 1;		///< タッチにより目的地が変更されている最中か？
	u32 bMove : 1;			///< 移動中フラグ
	u32 bOwn : 1;			///< 自滅判定フラグ
	u32 DummyBit : 2;
	u8 FallFrame;			///< 落下フレームカウンタ
	u8 NetID;
	u8 PokeID;
	u8 DummyByte[1];
} CATCH_POKE;

//--------------------------------------------------------------
///	参加チーム管理ワーク
//==============================================================
typedef struct {
	POS_DATA TouchPos;
	TP_STATE_CATCH TpState;
	CATCH_POKE CatchPoke[ ENTRY_MAX ];
	u32 NetID : 2;
	u32 Score : 16;			///< ゲームで得た得点
	u32 DummyBit : 14;
} TEAM_DATA;

//--------------------------------------------------------------
///	UFO管理ワーク
//==============================================================
typedef struct {
	// [IN]
	TEAM_DATA* TeamDataHead;
	// [PRIVATE]
	UFO_DATA UFO[ UFO_ID_MAX ];
	u32 CreateTimer : 8;
	u32 CreateLevel : 4;
	u32 DummyBit : 20;
} UFO_CNT_DATA;

//--------------------------------------------------------------
///	親がローカルで使用するデータ
//==============================================================
typedef struct {
	u8 PokeInvalidCollision[ ACT_POKE_MAX ][ ACT_POKE_MAX ];
	TEAM_DATA TeamData[ ENTRY_MEMBER_NUM_MAX ];
	UFO_CNT_DATA UfoCntData;
	int GameTimer;
} SERVER_WORK;

#define UFO_CAP_NUM (2)
//--------------------------------------------------------------
///	UFO描画ワーク
//==============================================================
typedef struct {
	CATS_ACT_PTR capUFO[ UFO_CAP_NUM ];		///< (0:上画面、1:下画面)
	CATS_ACT_PTR capShadow[ UFO_CAP_NUM ];	///< (0:上画面、1:下画面)
	CATS_ACT_PTR capScore;
	CATS_ACT_PTR capEff;
	u32 ScaleCount : 16;
	u32 StatePre : 8;
	u32 DummyBit : 8;
} UFO_DRAW;

//--------------------------------------------------------------
///
//==============================================================
typedef struct {
	// [IN]
	POKE_ACT_PTR PokeAct;
	// [PRIVATE]
	TCB_PTR tcb;
	f32 ScaleY;
	u16 Timer;
	u16 Seq;
} JUMP_FAILED_WORK;

//--------------------------------------------------------------
///	ポケモン描画ワーク
//==============================================================
typedef struct {
	// [PRIVATE]
	CATS_ACT_PTR capSmoke;
	JUMP_FAILED_WORK wkJumpFailed;
	fx32 fxScale;
	u32 JumpFrame : 8;
	u32 FallFrame : 8;
	u32 bJumping : 1;
	u32 bJumpFailed : 1;
	u32 bFalling : 1;
	u32 bFallBitPre : 1;
	u32 DummyBit : 12;
} POKE_DRAW;

//--------------------------------------------------------------
///	通信用ビューア
//==============================================================
typedef struct {
	// [IN]
	CATCH_SUB_CNT_PTR cntSub;
	// [PRIVATE]
	UFO_DRAW drawUfo[ UFO_ID_MAX ];
	POKE_DRAW drawPoke[ ACT_POKE_MAX ];
	u16 ScorePre[ ENTRY_MEMBER_NUM_MAX ];
} COMM_VIEWER_WORK;

//--------------------------------------------------------------
///	BG転送アニメ用ワーク
//==============================================================
typedef struct {
	u8 Counter;
	u8 Offset;
} BG_TRANS_WORK;

//--------------------------------------------------------------
///	UFOを手に入れたポケモンの情報
//==============================================================
typedef struct {
	POS_DATA pos;
	u8 NetID;
	u8 PokeID;
	u8 DummyByte[2];
} UFO_GET_POKE;

//--------------------------------------------------------------
///	画面揺らしワーク
//==============================================================
typedef struct {
	// [IN]
	CATS_SYS_PTR csp;
	GF_BGL_INI* bgl;
	// [PRIVATE]
	TCB_PTR					tcbShake;
	s8						ShakeVal;
	s8						ShakeFrame;
	BOOL					ShakeVec;
} SHAKE_WORK;

//--------------------------------------------------------------
///	メインワーク
//==============================================================
typedef struct PKTHLN_CATCH_tag {
	// --- in ---
	HEAPID HeapID;
	PKTHLN_PTR PkthlnWork;
	// --- gf system pointer ---
	GF_BGL_INI*	bgl;
	CATS_SYS_PTR csp;
	CATS_RES_PTR crp;
	WORDSET* WordSet;
	MSGDATA_MANAGER* MsgMan;
	// -- pokethlon system pointer --
	CMN_RES_CNT_PTR		CmnResCntPtr;
	POKE_ACT_CNT_PTR	PokeActCntPtr;
	// --- private ---
	GF_BGL_BMPWIN		Win;
	CATCH_POKE_PARAM	CatchPokeParam[ ACT_POKE_MAX ];
	CATCH_SUB_CNT_PTR	cntSub;
	CATCH_AI_CNT_PTR	cntAI;
	SERVER_WORK			wkServer;
	COMM_VIEWER_WORK	wkViewer;
	BG_TRANS_WORK		wkBGTrans;
	SHAKE_WORK			wkShake;
} PKTHLN_CATCH;

//-----------------------------------------------------------------------------
/**
 *	@brief	画面揺らしワーク
 *
 *	@param	TCB_PTR tcb
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void TCB_ShakeTask( TCB_PTR tcb, void* work )
{
	SHAKE_WORK* wk = work;
	int vec = ( wk->ShakeVec == 0 ) ? 1 : -1;
	int Pos = wk->ShakeVal * vec;

//	HOSAKA_PRINT("shake vec:%d Pos:%d \n", vec, Pos);

	GF_BGL_ScrollReq( wk->bgl, BG_FRM_M_LAND, GF_BGL_SCROLL_Y_SET, SCR_DEF_OFS + Pos );
	GF_BGL_ScrollReq( wk->bgl, BG_FRM_M_TRANS, GF_BGL_SCROLL_Y_SET, Pos );
	CLACT_U_SetMainSurfaceMatrix( CATS_EasyRenderGet( wk->csp ), 0, -1*Pos*FX32_ONE );

	if( wk->ShakeFrame % 2 == 1 )
	{
		wk->ShakeVal -= 1;
	}

	wk->ShakeVec ^= 1;

	if( --wk->ShakeFrame <= 0 )
	{
		GF_BGL_ScrollReq( wk->bgl, BG_FRM_M_LAND, GF_BGL_SCROLL_Y_SET, SCR_DEF_OFS );
		GF_BGL_ScrollReq( wk->bgl, BG_FRM_M_TRANS, GF_BGL_SCROLL_Y_SET, 0 );
		CLACT_U_SetMainSurfaceMatrix( CATS_EasyRenderGet( wk->csp ), 0, 0 );

		HOSAKA_PRINT("TCB SHAKE END\n");
		wk->tcbShake = NULL;
		TCB_Delete( tcb );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	画面揺らしTCB終了チェック
 *
 *	@param	SHAKE_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL Shake_CheckEnd( SHAKE_WORK* wk )
{
	GF_ASSERT( wk );
	return ( wk->tcbShake == NULL );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	画面揺らし 初期化
 *
 *	@param	SHAKE_WORK* wk
 *	@param	bgl
 *	@param	csp
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Shake_Init( SHAKE_WORK* wk, GF_BGL_INI* bgl, CATS_SYS_PTR csp )
{
	wk->bgl = bgl;
	wk->csp = csp;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	画面揺らしTCB登録関数
 *
 *	@param	PKTHLN_BREAK_PTR ptr
 *	@param	ShakeVal
 *	@param	ShakeFrame
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void StartShakeTask( SHAKE_WORK* wk, u8 ShakeVal, u8 ShakeFrame )
{
	GF_ASSERT( wk->bgl );
	GF_ASSERT( wk->csp );

	// TCB強制終了
	if( wk->tcbShake )
	{
		HOSAKA_PRINT("SHAKE TCB強制終了\n");
		TCB_Delete( wk->tcbShake );
	}

	HOSAKA_PRINT("TCB SHAKE START\n");

	wk->ShakeVec = 0;
	wk->ShakeVal = ShakeVal;
	wk->ShakeFrame = ShakeFrame;
	wk->tcbShake = TCB_Add( TCB_ShakeTask, wk, 2 );
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	TCB_PTR tcb
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void TCB_JumpFailed( TCB_PTR tcb, void* work )
{
	JUMP_FAILED_WORK* wk = work;

	switch( wk->Seq )
	{
		case 0 :
			wk->ScaleY = POKE_DEF_SCALE_F - (0.3 * wk->Timer);
			if( wk->Timer > 1 )
			{
				wk->Timer = 0;
				wk->Seq++;
			}
			else
			{
				PokeAct_SetScale( wk->PokeAct, POKE_DEF_SCALE_F, wk->ScaleY );
				wk->Timer++;
			}
			break;
		case 1 :
			wk->ScaleY = POKE_DEF_SCALE_F + (0.3 * wk->Timer);
			if( wk->Timer > 1 )
			{
				// 終了
				wk->tcb = NULL;
				PokeAct_SetScale( wk->PokeAct, POKE_DEF_SCALE_F, POKE_DEF_SCALE_F );
				TCB_Delete( tcb );
			}
			else
			{
				PokeAct_SetScale( wk->PokeAct, POKE_DEF_SCALE_F, wk->ScaleY );
				wk->Timer++;
			}
			break;

		default : GF_ASSERT(0);
	}

}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	JUMP_FAILED_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void StartJumpFailedTask( JUMP_FAILED_WORK* wk, POKE_ACT_PTR poke_act )
{
	if( wk->tcb )
	{
		TCB_Delete( wk->tcb );
	}

	wk->PokeAct = poke_act;
	wk->Timer = 0;
	wk->Seq = 0;
	wk->tcb = TCB_Add( TCB_JumpFailed, wk, 0 );
}

//=============================================================================
/**
 *							プロトタイプ宣言
 */
//=============================================================================
// -- prototype --
static void Poke_SetAffineVec( POKE_ACT_PTR poke_ptr, BOOL bCenter );
static BOOL Poke_CheckCircle(CATCH_POKE * poke1, CATCH_POKE * poke2);
static void Poke_StartJump( CATCH_POKE* pCPoke );
static BOOL Poke_IsHitActive( CATCH_POKE* pCPoke );
static void Poke_SetLastPos( CATCH_POKE* pCPoke, POS_DATA* Pos );
static u8 Poke_GetDir( VecFx32* norm_dir_vec );
static void Poke_Move( CATCH_POKE* pCPoke, PKTHLN_PTR work );
static BOOL Poke_CheckFall( CATCH_POKE* pCPoke, const fx32 fxPosX, const fx32 fxPosY );
static void Poke_Revive( CATCH_POKE* pCPoke );
static void Poke_Calc( CATCH_POKE* pCPoke, PKTHLN_PTR work );
static s8 CheckPokeTouch( CATCH_POKE* pCPoke, s16 TpX, s16 TpY );
static void UFO_COMM_Draw( COMM_VIEWER_WORK* wk, CATCH_COMM_PARENT_PTR parent, PKTHLN_PTR work );
static void POKE_COMM_Draw( COMM_VIEWER_WORK* wk, CATCH_COMM_PARENT_PTR parent, PKTHLN_PTR work );

s16 Catch_GetUfoPosX( s16 pos_y, u16 vec );
const UFO_DATA* Catch_GetUfoData( PKTHLN_CATCH_PTR ptr, u8 idx );
void Catch_GetPokeNowPos( PKTHLN_CATCH_PTR ptr, u8 NetID, u8 PokeID, POS_DATA* outPos, int* outRange );
u8 Catch_GetNowRank( PKTHLN_PTR work, u8 NetID );
void Catch_SetPokeMovePos( PKTHLN_CATCH_PTR ptr, POS_DATA* Pos, u8 NetID, u8 PokeID );
void Catch_SetPokeJump( PKTHLN_CATCH_PTR ptr, u8 NetID, u8 PokeID );
u8 Catch_GetScore( PKTHLN_CATCH_PTR ptr, u8 NetID );
static void SetVramBank(void);
static u32 CalcPow2( u32 num );
static void CalcZeroConverge( fx32* p_num, fx32 dec );
static u32 CalcJumpPosZ( CATCH_POKE_PARAM* pCPokeParam, u32 NowFrame, f32* outScale );
static void VEC_ZeroConverge( VecFx32* pVec, fx32 decX, fx32 decY );
static void VEC_Clamp( VecFx32* vec, fx32 max );
static void SetRecordStr( PKTHLN_PTR work, const int inPoint );
static void OBJ_Create( PKTHLN_CATCH_PTR ptr );
static void OBJ_Delete( PKTHLN_CATCH_PTR ptr );
static void OBJ_Finish( PKTHLN_CATCH_PTR ptr );
static void OBJ_LoadRes( PKTHLN_CATCH_PTR ptr );
static CATS_ACT_PTR OBJ_AddCapCmn( CATS_SYS_PTR csp, CATS_RES_PTR crp, s16 px, s16 py, u16 anime, u16 pri, BOOL bMainLCD );
static CATS_ACT_PTR OBJ_AddCapMain( CATS_SYS_PTR csp, CATS_RES_PTR crp, s16 px, s16 py, u16 anime, u16 pri );
static void BG_Init( PKTHLN_CATCH_PTR ptr );
static void BG_Delete( PKTHLN_CATCH_PTR ptr );
static void BG_LoadRes( PKTHLN_CATCH_PTR ptr );
static void BG_TransAnimeProc( BG_TRANS_WORK* wk, GF_BGL_INI* ini, HEAPID HeapID );
static void CommMain( PKTHLN_PTR work );
static BOOL MainProc( PKTHLN_PTR work );
static void SetCatchPokeParam( PKTHLN_PTR work );
static CATCH_POKE_PARAM* GetCatchPokeParam( PKTHLN_PTR work, u8 NetID, u8 PokeIdx );
static u16 GetJumpFrame( const CATCH_POKE_PARAM* pCPokeParam );
static u8 UfoStateToScore( UFO_DATA* ufo );
static void TeamCnt_Create( PKTHLN_CATCH_PTR ptr );
static void TeamCnt_Init( PKTHLN_CATCH_PTR ptr );
static void TeamCnt_CalcPokeCollision( PKTHLN_PTR work );
static void TeamCnt_Calc( TEAM_DATA* pTeamDataHead, PKTHLN_PTR work );
static void TeamCnt_SetCommData( SERVER_WORK* pServer, PKTHLN_PTR work );
static void UFO_Init( UFO_DATA* ufo, u8 SpeedY, u8 ID );
static void UFO_Delete( UFO_DATA* ufo );
static BOOL UFO_CheckHitPoke( UFO_DATA* ufo, TEAM_DATA* TeamDataHead, UFO_GET_POKE* outPoke );
static BOOL CheckHitAreaAbuttals( POS_DATA* pos, s16 abuttalsY );
static void UFO_SetScore( UFO_DATA* ufo, TEAM_DATA* TeamDataHead, UFO_GET_POKE* getPoke );
static void UFO_Calc( UFO_DATA* ufo, CATCH_COMM_UFO* commUfo, TEAM_DATA* TeamDataHead );
static void UFO_CNT_Init( UFO_CNT_DATA* cnt, TEAM_DATA* TeamDataHead );
static void UFO_CNT_SetNext( UFO_CNT_DATA* cnt, u32 GameSec );
static void UFO_CNT_Calc( UFO_CNT_DATA* cnt, COMM_EVENT_COMMON_DATA* data, u32 GameSec );
static void COMM_VIEWER_Init( COMM_VIEWER_WORK* wk, CATS_SYS_PTR csp, CATS_RES_PTR crp, CATCH_SUB_CNT_PTR cntSub );
static void COMM_VIEWER_Draw( COMM_VIEWER_WORK* wk, PKTHLN_PTR work );
static void COMM_VIEWER_Exit( COMM_VIEWER_WORK* wk );
static void CreateBmpWin( PKTHLN_CATCH_PTR ptr );


//-----------------------------------------------------------------------------
/**
 *	@brief	アフィン座標設定
 *
 *	@param	POKE_ACT_PTR poke_act
 *	@param	bCenter	TRUE:ポケモンの中心 FALSE:足元
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Poke_SetAffineVec( POKE_ACT_PTR poke_ptr, BOOL bCenter )
{
	const MONS_INFO *info;
	PCLACT_PTR	pclact_ptr = PokeAct_GetPclActPtr(poke_ptr);
	int space = PCLACT_GetSpaceHeight(pclact_ptr);
	int size;
	VecFx32 aff_vec = {0,0,0};

	info = PCLACT_GetMonsInfo(pclact_ptr);

	if (info->CellType)
	{
		size = POKE_L_SIZE;
		PokeAct_SetAffine(poke_ptr, CLACT_AFFINE_NORMAL);
	}
	else
	{
		size = POKE_S_SIZE;
		PokeAct_SetAffine(poke_ptr, CLACT_AFFINE_DOUBLE);
	}

	if( bCenter )
	{
		aff_vec.x = (size/2)*FX32_ONE;
		aff_vec.y = (space+(size-space)/2)*FX32_ONE;
	}
	else
	{
		aff_vec.x = (size/2)*FX32_ONE;
		aff_vec.y = (size-1)*FX32_ONE;
	}

	//アフィン座標セット
	PokeAct_SetAffineVec(poke_ptr, &aff_vec);
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポケモン同士の当たり判定
 *
 *	@param	* poke1	ポケ1
 *	@param	* poke2	ポケ2
 *
 *	@return	TRUEでヒット
 */
//-----------------------------------------------------------------------------
static BOOL Poke_CheckCircle(CATCH_POKE * poke1, CATCH_POKE * poke2)
{
	int r1;
	int r2;
	fx32 len;
	VecFx32 vec, vec1, vec2;
	fx32 range;

	PokeAct_GetHitData(poke1->PokeActPtr, poke1->NowPos.x, poke1->NowPos.y, &vec1.x, &vec1.y, &r1);
	PokeAct_GetHitData(poke2->PokeActPtr, poke2->NowPos.x, poke2->NowPos.y, &vec2.x, &vec2.y, &r2);

	range = (r1+r2)*FX32_ONE;

	vec1.z = 0;
	vec2.z = 0;

	VEC_Subtract( &vec1, &vec2, &vec );
	//方向ベクトルの長さを取得
	len = VEC_Mag(&vec);

	if (len <= range){
		return TRUE;
	}
	return FALSE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン ジャンプ開始処理
 *
 *	@param	CATCH_POKE* pCPoke
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Poke_StartJump( CATCH_POKE* pCPoke )
{
	CATCH_POKE_PARAM* p_prm = GetCatchPokeParam( pCPoke->work, pCPoke->NetID, pCPoke->PokeID );

	if( p_prm->JumpLevel )
	{
		// AP:ジャンプ
		PTFrame_AddActionPoint( pCPoke->work, pCPoke->NetID, pCPoke->PokeID, ADD_TYPE_JUMP, 1 );
		pCPoke->JumpFrame = GetJumpFrame( pCPoke->cpp );
		pCPoke->State = POKE_ST_JUMP;
	}

	// 演出が入るため、ジャンプできない場合もジャンプしようとした情報は送信する
	pCPoke->JumpSendFrame = 10;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモンの衝突判定が有効か？
 *
 *	@param	CATCH_POKE* pCPoke
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL Poke_IsHitActive( CATCH_POKE* pCPoke )
{
	GF_ASSERT(pCPoke);
	return ( pCPoke->State == POKE_ST_ALIVE || pCPoke->State == POKE_ST_JUMP );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン 目的地設定
 *
 *	@param	CATCH_POKE* pCPoke
 *	@param	Pos
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Poke_SetLastPos( CATCH_POKE* pCPoke, POS_DATA* Pos )
{
	pCPoke->LastPos.x = Pos->X * FX32_ONE;
	pCPoke->LastPos.y = Pos->Y * FX32_ONE;
	pCPoke->bSetPos = 1;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン 向き取得
 *
 *	@param	VecFx32* norm_dir_vec
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u8 Poke_GetDir( VecFx32* norm_dir_vec )
{
	// ZX平面
	u16 rad;
	VecFx32 vec = {0,0,FX32_ONE};
	VecFx32 xz_vec = {0};
	u8 dir;

	xz_vec.x = norm_dir_vec->y;
	xz_vec.z = norm_dir_vec->x;
	xz_vec.y = 0;

	rad = GetRad(&vec, &xz_vec);

	if ( (0<=rad&&rad<=0x2000)||(0xe000<=rad) ){	//右
		dir = POKE_DIR_RIGHT;
	}else if(0x2000<rad&&rad<0x6000){		//下
		dir = POKE_DIR_DOWN;
	}else if(0x6000<=rad&&rad<=0xa000){		//左
		dir = POKE_DIR_LEFT;
	}else{	//(0xa000<rad&&rad<0xe000)		//上
		dir = POKE_DIR_UP;
	}

//	HOSAKA_PRINT( "[%d,%d] Dir:%d \n",pCPoke->ID/ENTRY_MAX, pCPoke->ID%ENTRY_MAX, pCPoke->Dir );
//
	return dir;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン 移動
 *
 *	@param	CATCH_POKE* pCPoke
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Poke_Move( CATCH_POKE* pCPoke, PKTHLN_PTR work )
{
	fx32 move;
	fx32 len;
	VecFx32 dir_vec;
	VecFx32 norm_dir_vec;
	VecFx32 move_vec;

	// 生存していなければ処理を飛ばす
	if( pCPoke->State == POKE_ST_NONE ){ return; }

	// 方向ベクトル取得
	VEC_Subtract( &pCPoke->LastPos, &pCPoke->NowPos, &dir_vec );
	// 方向ベクトルの長さを取得
	len = VEC_Mag(&dir_vec);

	// 移動フラグを算出
	pCPoke->bMove = (len > 0);

	//--------------------------------------------------------
	// ふっとび・ふんばり処理
	//--------------------------------------------------------
	if( pCPoke->bPush )
	{
		VecFx32 dirNorm = {0};
		VecFx32 vecDmy = {0};
		VecFx32 vecHold;
		fx32 fxHold = POKE_PUSH_DEC_FX;

		// ふっとばされている方向を検出
		VEC_Normalize(&pCPoke->PushVec, &dirNorm);

		// ふんばり力を分解
		VEC_MultAdd( fxHold, &dirNorm, &vecDmy, &vecHold );

		vecHold.x = MATH_IAbs(vecHold.x);
		vecHold.y= MATH_IAbs(vecHold.y);

		// タッチしている方向にパワー分ふんばる
		if( pCPoke->bSetPos )
		{
			VecFx32 vecTouchHold;
			fx32 fxPower = pCPoke->cpp->fxPower / 100;

			VEC_Normalize(&dir_vec, &norm_dir_vec);

			// ふんばり力を分解
			VEC_MultAdd( fxPower, &pCPoke->NormDirVec, &vecDmy, &vecTouchHold );

			vecHold.x += MATH_IAbs(vecTouchHold.x);
			vecHold.y += MATH_IAbs(vecTouchHold.y);
		}

		VEC_ZeroConverge( &pCPoke->PushVec, vecHold.x, vecHold.y );
		VEC_Add( &pCPoke->NowPos, &pCPoke->PushVec, &pCPoke->NowPos);

#ifdef PM_DEBUG
#ifdef DEBUG_PRINT_PUSH
		if( pCPoke->PushVec.x != 0 || pCPoke->PushVec.y != 0 )
		{
			HOSAKA_PRINT("[%d]PushVec:{%f,%f} Hold{%f,%f} \n", pCPoke->ID,
				FX_FX32_TO_F32(pCPoke->PushVec.x),
				FX_FX32_TO_F32(pCPoke->PushVec.y),
				FX_FX32_TO_F32(vecHold.x),
				FX_FX32_TO_F32(vecHold.y) );
		}
#endif
#endif

		// 目的地更新
		pCPoke->LastPos = pCPoke->NowPos;

		// プッシュ終了判定
		if( pCPoke->PushVec.x == 0 && pCPoke->PushVec.y == 0 )
		{
			pCPoke->bPush = 0;
		}
		else
		{
			// プッシュ中は処理を打ち切る
			return;
		}
	}

	// 動いていなければ処理を打ち切る
	if( pCPoke->bMove == FALSE )
	{
		return;
	}

	//--------------------------------------------------------
	// 方向変更・移動処理
	//--------------------------------------------------------
	// 正規化
	VEC_Normalize(&dir_vec, &norm_dir_vec);

	// ノックバック時に向きを変更しなくする
	if( pCPoke->bPush == 0 )
	{
		// 方向ベクトルから向きを決定
		pCPoke->Dir = Poke_GetDir( &norm_dir_vec );
	}

	move = pCPoke->cpp->fxMove;

	// 方向ベクトルの長さが、スピード長以下ならば速度係数を無視
	// 誤差修正
	if( len <= move )
	{
		move_vec = dir_vec;
	}
	else
	{
		// スピード調整
		VecFx32 add = {0,0,0};
		VEC_MultAdd( move, &norm_dir_vec, &add, &move_vec);
	}

	// 通常移動
	VEC_Add( &pCPoke->NowPos, &move_vec, &pCPoke->NowPos);

	// 正規化された方向ベクトルを保持
	pCPoke->NormDirVec = norm_dir_vec;

}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン 落下判定
 *
 *	@param	CATCH_POKE* pCPoke
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL Poke_CheckFall( CATCH_POKE* pCPoke, const fx32 fxPosX, const fx32 fxPosY )
{
	int sx, sy;

	// タッチ座標から影座標を算出
	PokeAct_GetShadowPosByTouchPos(pCPoke->PokeActPtr,
			fxPosX >> FX32_SHIFT, fxPosY >> FX32_SHIFT,
			&sx, &sy );

	// 回り込んでいたら落下したことにする
	if( sx <= 0 || sy <= 0 || sx >= 255 || sy >= 255 )
	{
		return TRUE;
	}

	return ( sx < RING_X_MIN || sx >= RING_X_MAX ||
			 sy < RING_Y_MIN || sy >= RING_Y_MAX );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン 復活処理
 *
 *	@param	CATCH_POKE* pCPoke
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Poke_Revive( CATCH_POKE* pCPoke )
{
	u8 ID = pCPoke->ID;
	int sx, sy;
	int tx, ty;

	sx = g_PokeInitPos[ ID / ENTRY_MAX ][ ID % ENTRY_MAX ].X;
	sy = g_PokeInitPos[ ID / ENTRY_MAX ][ ID % ENTRY_MAX ].Y;

	PokeAct_GetTouchPosByShadowPos( pCPoke->PokeActPtr, sx, sy, &tx, &ty );

	pCPoke->NowPos.x = tx * FX32_ONE;
	pCPoke->NowPos.y = ty * FX32_ONE;
	pCPoke->LastPos.x = tx * FX32_ONE;
	pCPoke->LastPos.y = ty * FX32_ONE;
	pCPoke->PushVec = (VecFx32){0,0,0};
	pCPoke->Dir = POKE_DIR_DOWN;
	pCPoke->bPush = 0;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン 主処理
 *
 *	@param	CATCH_POKE* pCPoke
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Poke_Calc( CATCH_POKE* pCPoke, PKTHLN_PTR work )
{
	switch( pCPoke->State )
	{
	case POKE_ST_REVIVE :
		pCPoke->State = POKE_ST_ALIVE;
		HOSAKA_PRINT("[%d,%d] Poke revive.\n",pCPoke->ID/ENTRY_MAX, pCPoke->ID%ENTRY_MAX );
		break;

	case POKE_ST_FALL :
		if( --pCPoke->FallFrame <= 0 )
		{
			// 復帰時にすぐ使えるように、
			// 状態フラグ以外はこの段階で復帰時の値を渡しておく
			Poke_Revive( pCPoke );
			pCPoke->State = POKE_ST_REVIVE;
		}
		break;

	case POKE_ST_ALIVE :
		Poke_Move( pCPoke, work );

		// 落下チェック
		if( Poke_CheckFall( pCPoke, pCPoke->NowPos.x, pCPoke->NowPos.y ) )
		{
			// AP:失敗
			PTFrame_AddActionPoint( pCPoke->work, pCPoke->NetID, pCPoke->PokeID, ADD_TYPE_FAIL, 1 );
			// AP:落下
			PTFrame_AddActionPoint( pCPoke->work, pCPoke->NetID, pCPoke->PokeID, ADD_TYPE_FALL, 1 );
			// AP:自滅
			if( pCPoke->bOwn )
			{
				PTFrame_AddActionPoint( pCPoke->work, pCPoke->NetID, pCPoke->PokeID, ADD_TYPE_OWN, 1 );
			}
			pCPoke->bOwn = 0;	// 自殺フラグクリア
			pCPoke->FallFrame = POKE_FALL_TIMER;
			pCPoke->State = POKE_ST_FALL;
			HOSAKA_PRINT("[%d,%d] Poke Fall.\n",pCPoke->ID/ENTRY_MAX, pCPoke->ID%ENTRY_MAX );
		}
		break;

	case POKE_ST_JUMP :
		// ジャンプ中
		if( --pCPoke->JumpFrame <= 0 )
		{
			pCPoke->State = POKE_ST_ALIVE;
		}

		Poke_Move( pCPoke, work );
		break;

	default : GF_ASSERT(0);
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモンをタッチしているか判定する
 *
 *	@param	CATCH_POKE* pCPoke	CatchPokeの先頭ポインタ
 *	@param	TpX						タッチX座標
 *	@param	TpY						タッチY座標
 *
 *	@retval	タッチしたポケモンのインデックス
 */
//-----------------------------------------------------------------------------
static s8 CheckPokeTouch( CATCH_POKE* pCPoke, s16 TpX, s16 TpY )
{
	enum{ LEN_MAX = GX_LCD_SIZE_X * FX32_ONE, };

	int ret_idx = ACT_POKE_MAX; // エラーコード
	int i;
	fx32 len[ ENTRY_MAX ] = { LEN_MAX, LEN_MAX, LEN_MAX };
	fx32 len_min = LEN_MAX;

	for( i=0; i<ENTRY_MAX; i++ )
	{
		if( PokeAct_CheckTouch(
					pCPoke[i].PokeActPtr,
					pCPoke[i].NowPos.x,
					pCPoke[i].NowPos.y,
					TpX, TpY ) )
		{
			VecFx32 vec = {0};
			vec.x = MATH_IAbs( TpX * FX32_ONE - pCPoke[i].NowPos.x );
			vec.y = MATH_IAbs( TpY * FX32_ONE - pCPoke[i].NowPos.y );
			len[i] = VEC_Mag(&vec);
			HOSAKA_PRINT( "touch len[%d] = %d \n",i, len[i] );
		}
	}

	// 最短距離探索
	for( i=0; i< ENTRY_MAX; i++ )
	{
		if( len[i] < len_min )
		{
			len_min = len[i];
			ret_idx = i;
			HOSAKA_PRINT( "touch ret len = %d \n", ret_idx );
		}
	}

	return ret_idx;
}

//--------------------------------------------------------------
///	UFO表示状態
//==============================================================
typedef enum {
	UFO_CAP_DISP_UP = 0,	///< 上画面に出現
	UFO_CAP_DISP_DOWN,		///< 下
	UFO_CAP_DISP_ALL,		///< 両方(o)
}UFO_CAP_DISP;

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO 表示非表示
 *
 *	@param	UFO_DRAW* drawUfo
 *	@param	disp
 *	@param	enable
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_DRAW_SetEnable( UFO_DRAW* drawUfo, UFO_CAP_DISP disp, int enable )
{
	switch( disp )
	{
	case UFO_CAP_DISP_UP :
		CATS_ObjectEnableCap( drawUfo->capUFO[0], enable );
		CATS_ObjectEnableCap( drawUfo->capUFO[1], !enable );
		CATS_ObjectEnableCap( drawUfo->capShadow[0], enable );
		CATS_ObjectEnableCap( drawUfo->capShadow[1], !enable );
		break;
	case UFO_CAP_DISP_DOWN :
		CATS_ObjectEnableCap( drawUfo->capUFO[0], !enable );
		CATS_ObjectEnableCap( drawUfo->capUFO[1], enable );
		CATS_ObjectEnableCap( drawUfo->capShadow[0], !enable );
		CATS_ObjectEnableCap( drawUfo->capShadow[1], enable );
		break;
	case UFO_CAP_DISP_ALL :
		CATS_ObjectEnableCap( drawUfo->capUFO[0], enable );
		CATS_ObjectEnableCap( drawUfo->capUFO[1], enable );
		CATS_ObjectEnableCap( drawUfo->capShadow[0], enable );
		CATS_ObjectEnableCap( drawUfo->capShadow[1], enable );
		break;
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO 拡大率設定
 *
 *	@param	UFO_DRAW* drawUfo
 *	@param	scale_f
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_DRAW_SetUfoScale( UFO_DRAW* drawUfo, f32 scale_f )
{
	CATS_ObjectScaleSetCap( drawUfo->capUFO[0], scale_f, scale_f );
	CATS_ObjectScaleSetCap( drawUfo->capUFO[1], scale_f, scale_f );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO獲得演出
 *
 *	@param	UFO_DRAW* drawUfo
 *	@param	state
 *	@param	px
 *	@param	py
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_VIEW_GetScore( UFO_DRAW* drawUfo, UFO_STATE state, s16 px, s16 py )
{
	int score_idx = state - UFO_ST_POINT_1;

	GF_ASSERT( score_idx < 4 );

	CATS_ObjectPosSetCap_SubSurface( drawUfo->capScore, px, py , OBJ_DISTANCE );
	CATS_ObjectPosSetCap_SubSurface( drawUfo->capEff, px, py , OBJ_DISTANCE );

	CATS_ObjectAnimeSeqSetCap( drawUfo->capScore, score_idx );
	CATS_ObjectAnimeReStartCap( drawUfo->capEff );
	CATS_ObjectEnableCap( drawUfo->capScore, CATS_ENABLE_TRUE );
	CATS_ObjectEnableCap( drawUfo->capEff, CATS_ENABLE_TRUE );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO獲得音（自分のみ）
 *
 *	@param	UFO_STATE state
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_SND_SelfGet( UFO_STATE state )
{
	u8 snd_seq;

	switch( state )
	{
		case UFO_ST_POINT_1 :
			snd_seq = THLON_CATCH_PITCH_LV1;
			break;
		case UFO_ST_POINT_2 :
			snd_seq = THLON_CATCH_PITCH_LV2;
			break;
		case UFO_ST_POINT_3 :
			snd_seq = THLON_CATCH_PITCH_LV3;
			break;
		case UFO_ST_POINT_5 :
			snd_seq = THLON_CATCH_PITCH_LV5;
			break;
		default : GF_ASSERT(0);
	}

	// UFO取得音
	Snd_SePitchPlay( SE_THLON_POINT1, snd_seq );

	HOSAKA_PRINT("UFO GET SE Pitch:%d \n", snd_seq);
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO 描画
 *
 *	@param	COMM_VIEWER_WORK* wk
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_COMM_Draw( COMM_VIEWER_WORK* wk, CATCH_COMM_PARENT_PTR parent, PKTHLN_PTR work )
{
	int i;
	u8 NetID;
	PKTHLN_CATCH_PTR ptr;
	CATS_SYS_PTR csp;
	CATS_RES_PTR crp;
	BOOL bLCDMain;
	s16 TotalDotY;
	s16 LcdDotX, LcdDotY;

	NetID = PTFrameGetCurrentID(work);
	ptr = PTFrame_GetEventWorkPtr(work);
	csp = ptr->csp;
	crp = ptr->crp;

	// UFO描画
	for( i=0; i<UFO_ID_MAX; i++ )
	{
		UFO_DRAW* drawUfo = &wk->drawUfo[i];
		CATCH_COMM_UFO* commUfo = &parent->Ufo[i];

		//=========================================================
		// 座標変換
		//=========================================================
		TotalDotY = commUfo->PosY * 8 / 2;

		// 画面外に掃ける演出
		if( commUfo->State == UFO_ST_DISPOUT )
		{
			TotalDotY += DISP_RANGE_Y;
		}

		LcdDotY = TotalDotY;

		bLCDMain = ( TotalDotY >= GX_LCD_SIZE_Y + DISP_DISTANCE );

		if( bLCDMain )
		{
			// 下画面Y座標
			LcdDotY -= GX_LCD_SIZE_Y + DISP_DISTANCE;
		}

		// Y座標からX座標を計算
		LcdDotX = Catch_GetUfoPosX( TotalDotY, commUfo->Vec );

		//=========================================================
		// UFO表示切替 Stateに依存
		//=========================================================
		if( commUfo->State == UFO_ST_NONE )
		{
			UFO_DRAW_SetEnable( drawUfo, UFO_CAP_DISP_ALL, FALSE );
			// スコア消す
			CATS_ObjectEnableCap( drawUfo->capScore, CATS_ENABLE_FALSE );
			CATS_ObjectEnableCap( drawUfo->capEff, CATS_ENABLE_FALSE );
		}
		// 点数状態
		else if( commUfo->State >= UFO_ST_POINT_1 && drawUfo->StatePre < UFO_ST_POINT_1 )
		{
			// UFOは消す
			UFO_DRAW_SetEnable( drawUfo, UFO_CAP_DISP_ALL, FALSE );

			// スコア表示
			UFO_VIEW_GetScore( drawUfo, commUfo->State, LcdDotX, LcdDotY + UFO_DIFF_SHADOW );

			// 自分がとった
			if( commUfo->GetPlayerID == NetID )
			{
				StartShakeTask( &ptr->wkShake, 4, 4 );	// 画面を揺らす
				UFO_SND_SelfGet( commUfo->State );
			}
			else
			{
				// 敵がとった場合スコア表示を無効
				CATS_ObjectEnableCap( drawUfo->capScore, CATS_ENABLE_FALSE );
			}

			// 取得音を鳴らす
			Snd_SePlay( SE_CATCH_UFO_GET );
		}
		// 通常状態IN
		else if( commUfo->State == UFO_ST_NORMAL )
		{
			UFO_DRAW_SetEnable( drawUfo, bLCDMain, TRUE );
			// スコア消す
			CATS_ObjectEnableCap( drawUfo->capScore, CATS_ENABLE_FALSE );
			CATS_ObjectEnableCap( drawUfo->capEff, CATS_ENABLE_FALSE );
		}

		// UFO生成処理
		if( drawUfo->StatePre == UFO_ST_NONE && commUfo->State == UFO_ST_NORMAL )
		{
			drawUfo->ScaleCount = 0;
			UFO_DRAW_SetUfoScale( drawUfo, UFO_DEF_SCALE_F );

			// UFO生成音
			Snd_SePlay( SE_CATCH_UFO_DISCHARGE );

			HOSAKA_PRINT("UFO[%d] Create \n", i);
		}

		// 移動
		if( commUfo->State == UFO_ST_NORMAL || commUfo->State == UFO_ST_DISPOUT )
		{
			f32 Scale;

			// 下画面
			if( bLCDMain && LcdDotX > 16 )
			{
				// 影切替
				CATS_ObjectAnimeSeqCheckSetCap( drawUfo->capShadow[bLCDMain], NANR_catch_obj_cmn_shade_l );
			}

			// 拡縮
			Scale = UFO_DEF_SCALE_F + FX_FX32_TO_F32( Sin360R( drawUfo->ScaleCount ) / 18 );
//			HOSAKA_PRINT("UfoScale:%f Sin360R:%f \n",Scale,  FX_FX32_TO_F32( Sin360R( drawUfo->ScaleCount) ) );
			drawUfo->ScaleCount += 10;
			UFO_DRAW_SetUfoScale( drawUfo, Scale );

			// 移動
			CATS_ObjectPosSetCap_SubSurface( drawUfo->capUFO[bLCDMain], LcdDotX, LcdDotY + UFO_DIFF_SHADOW, OBJ_DISTANCE );
			CATS_ObjectPosSetCap_SubSurface( drawUfo->capShadow[bLCDMain], LcdDotX, LcdDotY, OBJ_DISTANCE );
		}

#ifdef DEBUG_UFO_HOOK
		if( sys.trg & PAD_BUTTON_DEBUG )
		{
			HOSAKA_PRINT("UFO[%d] get posY:%d view pos {%d, %d} state:%d bLCDMain:%d\n",
					i, commUfo->PosY, LcdDotX, LcdDotY, commUfo->State, bLCDMain );
		}
#endif

		// 前回の値を保持
		drawUfo->StatePre = commUfo->State;
	}
}

//--------------------------------------------------------------
///	Y軸ソート用データ
//==============================================================
typedef struct {
	u8 PosY;
	POKE_ACT_PTR act;
} POKE_PRI_SORT;

//-----------------------------------------------------------------------------
/**
 *	@brief	Y軸ソート用の比較関数
 *
 *	@param	void* elem1
 *	@param	elem2
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static s32 PokePriSort( void* elem1, void* elem2 )
{
	POKE_PRI_SORT* p1 = (POKE_PRI_SORT*)elem1;
	POKE_PRI_SORT* p2 = (POKE_PRI_SORT*)elem2;

	if( p1->PosY == p2->PosY )
	{
		return 0;
	}
	else if( p1->PosY < p2->PosY )
	{
		return 1;
	}
	else
	{
		return -1;
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン描画
 *
 *	@param	COMM_VIEWER_WORK* wk
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void POKE_COMM_Draw( COMM_VIEWER_WORK* wk, CATCH_COMM_PARENT_PTR parent, PKTHLN_PTR work )
{
	enum{ COMM_FALL_SYNC = 6, };

	int i;
	PKTHLN_CATCH_PTR ptr;
	POKE_PRI_SORT sort[ACT_POKE_MAX] = {0};

	ptr = PTFrame_GetEventWorkPtr(work);

	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		POKE_DRAW* pPokeDraw = &wk->drawPoke[i];
		POKE_ACT_PTR poke_act = PokeAct_GetPokeActPtr( ptr->PokeActCntPtr, i );
		int sx, sy;
		int px, py;

		GF_ASSERT( pPokeDraw );
		GF_ASSERT( poke_act );

		sx = parent->PokeX[i];
		sy = parent->PokeY[i];

		// タッチ座標を取得
		PokeAct_GetTouchPosByShadowPos( poke_act, sx, sy, &px, &py );

		// Y軸ソートのための情報を保持
		sort[i].PosY = sy;
		sort[i].act = poke_act;

		// 落下／復活 検出
		{
			u8 bFall = ( parent->FallBit >> i ) & 0x1;

			// 落下
			if( bFall == 1 && pPokeDraw->bFallBitPre == 0 )
			{
				HOSAKA_PRINT("[%d,%d] comm Poke Fall start .\n", i/ENTRY_MAX, i%ENTRY_MAX );
				// 一時的にアフィン中心座標をポケモンの中心に
				Poke_SetAffineVec( poke_act, TRUE );
				pPokeDraw->bFalling = 1;
				pPokeDraw->FallFrame = COMM_FALL_SYNC;
				pPokeDraw->fxScale = FX32_CONST(1);
				// 落下音
				Snd_SePlay( SE_CATCH_FALL );
			}
			else
			// 復活
			if( bFall == 0 && pPokeDraw->bFallBitPre == 1 )
			{
				// 煙再生
				CATS_ObjectPosSetCap_SubSurface( pPokeDraw->capSmoke, px, py, OBJ_DISTANCE );
				CATS_ObjectEnableCap( pPokeDraw->capSmoke, CATS_ENABLE_TRUE );
				CATS_ObjectAnimeReStartCap( pPokeDraw->capSmoke );

				// アフィン中心座標を足元
				Poke_SetAffineVec( poke_act, FALSE );
				PokeAct_SetScale( poke_act, POKE_DEF_SCALE_F, POKE_DEF_SCALE_F );

				// ポケモン表示
				PokeAct_DispCnt( poke_act, TRUE );

				pPokeDraw->bFalling = 0;

				// 復活音
				Snd_SePlay( SE_CATCH_CHANGE_IN2 );

				HOSAKA_PRINT("[%d,%d] comm Poke Revive start !\n", i/ENTRY_MAX, i%ENTRY_MAX );
			}

			// 前回のビット状態を保持
			pPokeDraw->bFallBitPre = bFall;
		}

		// 落下処理
		if( pPokeDraw->bFalling )
		{
			if( --pPokeDraw->FallFrame <= 0 )
			{
				PokeAct_DispCnt( poke_act, FALSE );
			}
			else
			{
				int poke_x, poke_y;
				f32 Scale;

				pPokeDraw->fxScale -= FX32_CONST( 0.1 );
				Scale = FX_FX32_TO_F32(pPokeDraw->fxScale);
				PokeAct_SetScale( poke_act, Scale, Scale );

				// タッチ座標から影座標を算出
				PokeAct_GetShadowPosByTouchPos( poke_act, parent->PokeX[i], parent->PokeY[i], &poke_x, &poke_y );

				// 子機処理：下への落下
				if( poke_y >= RING_Y_MAX )
				{
					int fall_y = COMM_FALL_SYNC - pPokeDraw->FallFrame;

					fall_y = fall_y * 4 + sy;

					PokeAct_SetPosTouch( poke_act, px, fall_y, TRUE );
				}
			}

			// 落下中はここで処理を打ち切る
			continue;
		}

		// 移動
		{
			u8 dir = (parent->DirBit>>(i*2)) & 0x3;	// 2ビットマスク

			PokeAct_SetPosTouch( poke_act, px, py, TRUE);
			PokeAct_SetDir( poke_act, dir+1 );
		}

		// ジャンプ開始検出
		if( ( parent->JumpBit >> i ) & 0x1 )
		{
			CATCH_POKE_PARAM* p_prm = GetCatchPokeParam( work, i/ENTRY_MAX, i%ENTRY_MAX );

			// 自分のポケモンだった場合、初回のみジャンプ音
			if( PTFrameGetCurrentID(work) == (i/ENTRY_MAX) && pPokeDraw->bJumping == 0 && pPokeDraw->bJumpFailed == 0 )
			{
				//	ディグダ判定
				if( p_prm->JumpLevel == 0 )
				{
					// 成功音
					Snd_SePlay( SE_PKTH_JUMP_FAILED );
				}
				else
				{
					// 失敗音
					Snd_SePlay( SE_CATCH_UP );
				}
			}

			//	ディグダ判定
			if( p_prm->JumpLevel == 0 )
			{
				// 失敗演出開始
				StartJumpFailedTask( &pPokeDraw->wkJumpFailed, poke_act );

				pPokeDraw->bJumpFailed = 1; ///< ジャンプ失敗フラグON
			}
			else
			{
				pPokeDraw->bJumping = 1; ///< ジャンプ開始フラグON
			}
		}
		else
		{
			pPokeDraw->bJumpFailed = 0;
		}

		// ジャンプ処理
		if( pPokeDraw->bJumping )
		{
			CATCH_POKE_PARAM* pCPokeParam;
			f32 Scale;
			u32 PosZ;

			pCPokeParam = GetCatchPokeParam( work, i/ENTRY_MAX, i%ENTRY_MAX );

			// 描画
			{
				PosZ = CalcJumpPosZ( pCPokeParam, pPokeDraw->JumpFrame, &Scale );

				PokeAct_SetPosTouch( poke_act, px, py + PosZ, FALSE);
				PokeAct_SetScale( poke_act, Scale, Scale );
			}

			// 終了判定
			if( ++pPokeDraw->JumpFrame > GetJumpFrame( pCPokeParam ) )
			{
				pPokeDraw->bJumping = 0; ///< ジャンプ終了
				pPokeDraw->JumpFrame = 0;
				// 念のため座標をリセット
				PokeAct_SetPosTouch( poke_act, px, py, FALSE);
				PokeAct_SetScale( poke_act, POKE_DEF_SCALE_F, POKE_DEF_SCALE_F );
			}
		}
	} // end of for ACT_POKE_MAX


	// Y軸ソート
	MATH_QSort( (void*)sort, ACT_POKE_MAX, sizeof(POKE_PRI_SORT), PokePriSort, NULL );
	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		GF_ASSERT( sort[i].act );
		PokeAct_SetPriority( sort[i].act, PRI_POKE + i );
	}
}

//=============================================================================
/**
 *								外部公開関数
 */
//=============================================================================
// --- Event Func ---
static BOOL CATCH_Func_Phase1(PKTHLN_PTR work, u8 *seq);
static BOOL CATCH_Func_Phase2(PKTHLN_PTR work, u8 *seq);
static BOOL CATCH_Func_Phase3(PKTHLN_PTR work, u8 *seq);

PKTHLN_FUNC CatchFuncTbl[] = {
	CATCH_Func_Phase1,
	CATCH_Func_Phase2,
	CATCH_Func_Phase3,
};

enum {
	CATCH_SEQ_PHASE1,
	CATCH_SEQ_PHASE2,
	CATCH_SEQ_PHASE3,
};

//-----------------------------------------------------------------------------
/**
 *	@brief	初期化シーケンス関数
 *
 *	@param	work
 *	@param	*seq
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL CATCH_Func_Phase1(PKTHLN_PTR work, u8* seq)
{
	PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);

	BG_TransAnimeProc( &ptr->wkBGTrans, ptr->bgl, ptr->HeapID );

	switch( *seq )
	{
	case 0 :
		// フェードイン
		WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEIN,
						WIPE_TYPE_FADEIN, WIPE_FADE_WHITE,
						WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );
		(*seq)++;
		/* fallthrow */

	case 1:
		if( WIPE_SYS_EndCheck() )
		{
			(*seq)++;
		}
		break;

	case 2:
		if( PTFrame_CountDown(work) )
		{
			PTFrame_SetNextFuncTblIdx(work, CATCH_SEQ_PHASE2);
			HOSAKA_PRINT("move main seq\n");
		}
		break;

	default : GF_ASSERT(0);
	}

	return FALSE;
}


//-----------------------------------------------------------------------------
/**
 *	@brief	レコードコールバック関数
 *
 *	@param	work
 *
 *	@retval	none
 */
//-----------------------------------------------------------------------------
static void RecCallBack(PKTHLN_PTR work)
{
	COMM_EVENT_COMMON_DATA * data;
	CATCH_COMM_PARENT_PTR parent;
	PKTHLN_CATCH_PTR ptr;

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	ptr = PTFrame_GetEventWorkPtr(work);

	//ニューレコード用にレコードをセット
	{
		u8 point;
		point = CatchSub_GetDispScore( ptr->cntSub );
		//フレームワークにニューレコードチェック用のレコード値をセット
		PTFrame_SetCheckRecord(work, point);
		SetRecordStr(work, point);
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	メインシーケンス関数
 *
 *	@param	work
 *	@param	*seq
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL CATCH_Func_Phase2(PKTHLN_PTR work, u8 *seq)
{
	PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);

	BG_TransAnimeProc( &ptr->wkBGTrans, ptr->bgl, ptr->HeapID );

	switch( *seq )
	{
	case 0:
		CommMain(work);
		if( MainProc(work) )
		{
			(*seq)++;
		}
		break;

	case 1:
		CommMain(work);

		// 上画面更新
		{
			COMM_EVENT_COMMON_DATA* data;
			CATCH_COMM_PARENT_PTR parent;

			data = PTFrame_GetEvtComCmnData(work);
			parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);

			CatchSub_UpdateScore( ptr->cntSub, parent->ScoreHeader, parent->Score );
		}

		if( PTFrame_DispEnd(work) )
		{
			// TCB終了待ち
			if( Shake_CheckEnd( &ptr->wkShake ) )
			{
				//フェードアウト
				WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEOUT,
							WIPE_TYPE_FADEOUT, WIPE_FADE_BLACK,
							WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );

				PTFrame_SetNextFuncTblIdx(work, CATCH_SEQ_PHASE3);
			}
		}
		break;


	default : GF_ASSERT(0);
	}

	return FALSE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	結果シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL CATCH_Func_Phase3(PKTHLN_PTR work, u8 *seq)
{
	PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);

//	BG_TransAnimeProc( &ptr->wkBGTrans, ptr->bgl, ptr->HeapID );

	switch( *seq )
	{
		case 0:
		if( WIPE_SYS_EndCheck() )
		{
			int netID = PTFrameGetCurrentID(work);
			PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);

			// 親がスコアを送信
			if( netID == COMM_PARENT_ID )
			{
				int i;

				for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
				{
					u16 Score = ptr->wkServer.TeamData[ i ].Score;
					PTFrame_SetEvtResultOrg( work, i, Score );
					HOSAKA_PRINT("[%d]Score:%d \n",i, Score);
				}
			}

			HOSAKA_PRINT("Next To ResultFunc \n");
			return TRUE;
		}
		break;

		default : GF_ASSERT(0);

	}
	return FALSE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	初期化関数
 *
 *	@param	PKTHLN_PTR work
 *	@param	pParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
PTH_RC PE_CATCH_InitFunc( PKTHLN_PTR work, void* pParam )
{
	PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);
	u8 seq = PTFrame_GetSubSeq(work);

	switch( seq )
	{
	case 0 :
		// ヒープ生成
		sys_CreateHeap( HEAPID_POKETHLON, HEAPID_PT_CATCH, CATCH_HEAP_SIZE );

		// BlankFunc Reset
		sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
		sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

		GF_Disp_GX_VisibleControlInit();
		GF_Disp_GXS_VisibleControlInit();
		GX_SetVisiblePlane( 0 );
		GXS_SetVisiblePlane( 0 );

		// VRAMバンク割り当て
		SetVramBank();

		// 下画面を3D面に
		sys.disp3DSW = DISP_3D_TO_SUB;
		GF_Disp_DispSelect();

		// アプリケーションメモリー
		ptr = PTFrame_AllocEventWork(work, sizeof(PKTHLN_CATCH));
		MI_CpuClear8(ptr, sizeof(PKTHLN_CATCH));

		// ヒープIDを保持
		ptr->HeapID = HEAPID_PT_CATCH;
		ptr->PkthlnWork = work;
		ptr->wkServer.GameTimer = GAME_TIME;

		// 次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 1:
		// BGLアロケーション
		ptr->bgl = GF_BGL_BglIniAlloc( ptr->HeapID );

		PTFrame_SetRecBGMask(work, BG_FRM_M_RSLT_MASK );

		// BG 初期化
		BG_Init( ptr );

		// BGリソースロード
		BG_LoadRes( ptr );

		CreateBmpWin( ptr );

		// 通信アイコンを起動
		WirelessIconEasyPokethlon( NNS_G2D_VRAM_TYPE_2DSUB );

		// CATS 生成
		OBJ_Create( ptr );

		// ポケアクター管理ワーク生成
		TeamCnt_Create( ptr );

		// 次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 2 :
		if( PokeAct_CheckActSetTask( ptr->PokeActCntPtr ) )
		{
			// CATS管理のOBJリソースをロード
			// ※ポケ、コモンアクターロード後に呼ぶこと
			OBJ_LoadRes( ptr );

			//カウントダウンアクター 初期化
			{
				CLACT_WORK_PTR	*act_adr;
				act_adr = PTFrame_SetCountDownByClSet( work, OBJ_DISTANCE, ptr->CmnResCntPtr, CATS_GetClactSetPtr(ptr->crp) );
				//プライオリティセット
				CLACT_DrawPriorityChg( *act_adr, PRI_COUNT );
			}

			// 次のシーケンスへ
			PTFrame_IncSubSeq(work);
		}
		break;
	case 3:
		{
			u8 NetID = PTFrameGetCurrentID(work);

			ptr->cntSub = CatchSub_Create( ptr->csp, ptr->crp, ptr->bgl, ptr->MsgMan, ptr->WordSet, NetID, ptr->HeapID, work );

			COMM_VIEWER_Init( &ptr->wkViewer, ptr->csp, ptr->crp, ptr->cntSub );

			ptr->cntAI = CatchAICnt_Create( work, ptr->HeapID );

			//▼マーカ初期化
			PTFrame_InitPosMarker(work);

			// 画面揺らし 初期化
			Shake_Init( &ptr->wkShake, ptr->bgl, ptr->csp );

			// VBlank Set
			PTFrame_SetDefaultVBlankFunc(ptr->bgl);

			//描画を許可
			PTFrame_SetDraw(work, TRUE);

			// ポケアクター初期化
			TeamCnt_Init( ptr );

			// サーバ初期化
			if ( PTFrameGetCurrentID(work) == COMM_PARENT_ID )
			{
				COMM_EVENT_COMMON_DATA* data;
				CATCH_COMM_PARENT_PTR parent;

				data = PTFrame_GetEvtComCmnData(work);
				parent = PKTHLN_CommPack_GetData(&data->SendShareData);

				parent->GameSec = ( ptr->wkServer.GameTimer + 30 ) / GAME_FPS;
				TeamCnt_SetCommData( &ptr->wkServer, work );
			}

			UFO_CNT_Init( &ptr->wkServer.UfoCntData, ptr->wkServer.TeamData );

			//ＯＢＪの表示
			GF_Disp_GX_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );
			GF_Disp_GXS_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );

			HOSAKA_PRINT("CATCH InitFunc called.\n");

			return PTH_RC_END;
		}
		break;

	default :GF_ASSERT(0);
	}

	return PTH_RC_LOOP;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	描画関数
 *
 *	@param	PKTHLN_PTR work
 *	@param	pParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
BOOL PE_CATCH_DrawFunc( PKTHLN_PTR work, void* pParam )
{
	PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);

	GF_ASSERT(ptr);

	CATS_Draw( ptr->crp );

	return TRUE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	競技結果計算関数
 *
 *	@param	PKTHLN_PTR work
 *	@param	pParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
BOOL PE_CATCH_ResultFunc( PKTHLN_PTR work, void* pParam )
{
	int i;
	RSLT_PTR pRes;

	pRes = PTFrame_GetResultPtr(work);
	RSLT_Setup( pRes );

	for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
	{
		int rec;

		rec = PTFrame_GetEvtResult(work, i );
		RSLT_SetResult( work, pRes, i, rec, 0, 3, msg_pkthln_rs_K5 );
	}
	// ソート
	RSLT_Sort(pRes, SORT_REC_LARGE);

	// 得点セット
	PTC_CalcPoint(pRes, PKTHLN_EVT_CATCH);

	//総得点に加算
	RSLT_AddTotalScore( pRes );

	// 競技得点セット
	RSLT_SetEvtScore( pRes, PKTHLN_EVT_CATCH );

	HOSAKA_PRINT("CATCH ResultFunc Called.\n");

	return TRUE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	終了関数
 *
 *	@param	PKTHLN_PTR work
 *	@param	pParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
BOOL PE_CATCH_EndFunc( PKTHLN_PTR work, void* pParam )
{
	PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);

	//▼マーカ終了
	PTFrame_EndPosMarker(work);

	CatchAICnt_Delete( ptr->cntAI );

	CatchSub_Delete( ptr->cntSub );

	COMM_VIEWER_Exit( &ptr->wkViewer );

	// CATS開放
	OBJ_Delete( ptr );

	// BG開放
	BG_Delete( ptr );

	WirelessIconEasyEnd();

	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

	// イベントワーク開放
	PTFrame_FreeEventWork(work);

	// 上下画面を元に戻しておく
	sys.disp3DSW = DISP_3D_TO_MAIN;
	GF_Disp_DispSelect();

	// ヒープ開放
	sys_DeleteHeap( HEAPID_PT_CATCH );

	HOSAKA_PRINT("CATCH EndFunc Called.\n");

	return TRUE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	s16 pos_y
 *	@param	vec
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
s16 Catch_GetUfoPosX( s16 pos_y, u16 vec )
{
	s16 ret;
	s16 sin;

	ret = pos_y * ( vec - 7 ) * 38 / 1000 + 128;
	sin = ( 4 * Sin360R( pos_y * 2 ) ) >> FX32_SHIFT;
	ret = ret + sin;

//	HOSAKA_PRINT("GetUfoPos=%d sin=%d\n",ret, sin );

	return ret;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	指定ポケモンが動作可能か（親のみ使用可）
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *	@param	NetID
 *	@param	PokeID
 *
 *	@retval	TRUE:操作可能
 */
//-----------------------------------------------------------------------------
BOOL Catch_GetPokeActiveFlag( PKTHLN_CATCH_PTR ptr, u8 NetID, u8 PokeID )
{
	CATCH_POKE* pCPoke;

	GF_ASSERT(ptr);
	GF_ASSERT(NetID < ENTRY_MEMBER_NUM_MAX);
	GF_ASSERT(PokeID < ENTRY_MAX);

	pCPoke = &ptr->wkServer.TeamData[NetID].CatchPoke[PokeID];

	return ( pCPoke->State == POKE_ST_ALIVE || pCPoke->State == POKE_ST_JUMP );
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *	@param	idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
const UFO_DATA* Catch_GetUfoData( PKTHLN_CATCH_PTR ptr, u8 idx )
{
	GF_ASSERT(ptr);
	GF_ASSERT( idx < UFO_ID_MAX );

	return &ptr->wkServer.UfoCntData.UFO[ idx ];
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *	@param	NetID
 *	@param	PokeID
 *	@param	outPos
 *	@param	outRange
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
void Catch_GetPokeNowPos( PKTHLN_CATCH_PTR ptr, u8 NetID, u8 PokeID, POS_DATA* outPos, int* outRange )
{
	CATCH_POKE* pCPoke;

	GF_ASSERT(ptr);
	GF_ASSERT(NetID < ENTRY_MEMBER_NUM_MAX);
	GF_ASSERT(PokeID < ENTRY_MAX);

	pCPoke = &ptr->wkServer.TeamData[NetID].CatchPoke[PokeID];

	outPos->X = pCPoke->NowPos.x >> FX32_SHIFT;
	outPos->Y = pCPoke->NowPos.y >> FX32_SHIFT;
	*outRange = PokeAct_GetHitRange( pCPoke->PokeActPtr );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	現在の順位を取得(親のみ使用可)
 *
 *	@param	PKTHLN_PTR work
 *	@param	NetID 順位。若い方が上(0-3)
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
u8 Catch_GetNowRank( PKTHLN_PTR work, u8 NetID )
{
	PKTHLN_CATCH_PTR ptr;
	u16 tempScore;
	u8 rank = 0;
	int i;

	GF_ASSERT(work);
	ptr = PTFrame_GetEventWorkPtr(work);
	GF_ASSERT(ptr);


	for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
	{
		u16 MyScore;
		u16 Score;

		MyScore = ptr->wkServer.TeamData[NetID].Score;
		Score = ptr->wkServer.TeamData[i].Score;

//		HOSAKA_PRINT("[%d]Score : %d \n", i, Score);

		if( i == NetID ){ continue; }


		// 自分より点を持っている奴がいたら順位を下げる
		if( MyScore < Score )
		{
			rank++;
		}
	}

//	HOSAKA_PRINT("[%d]Get Rank : %d \n", NetID, rank);

	return rank;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモンの目的地をフック(親のみ使用可)
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *	@param	Pos
 *	@param	NetID
 *	@param	PokeID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
void Catch_SetPokeMovePos( PKTHLN_CATCH_PTR ptr, POS_DATA* Pos, u8 NetID, u8 PokeID )
{
	CATCH_POKE* pCPoke = &ptr->wkServer.TeamData[ NetID ].CatchPoke[ PokeID ];
	Poke_SetLastPos( pCPoke, Pos );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモンのジャンプ開始命令をフック(親のみ使用可)
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *	@param	NetID
 *	@param	PokeID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
void Catch_SetPokeJump( PKTHLN_CATCH_PTR ptr, u8 NetID, u8 PokeID )
{
	CATCH_POKE* pCPoke = &ptr->wkServer.TeamData[ NetID ].CatchPoke[ PokeID ];
	Poke_StartJump( pCPoke );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	各チームの得点を取得(親のみ使用可)
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *	@param	NetID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
u8 Catch_GetScore( PKTHLN_CATCH_PTR ptr, u8 NetID )
{
	return ptr->wkServer.TeamData[ NetID ].Score;
}

//=============================================================================
/**
 *								static関数
 */
//=============================================================================

//--------------------------------------------------------------------------------------------
/**
 * VRAM設定		ポケスロンでは、ポケモン表示だけで0x30000必要となる。
 * VRAM_AB(0x40000)でないとはいらん
 *
 * @param	none
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetVramBank(void)
{
	GF_BGL_DISPVRAM tbl = {
		GX_VRAM_BG_64_E,				// メイン2DエンジンのBG
		GX_VRAM_BGEXTPLTT_NONE,			// メイン2DエンジンのBG拡張パレット

		GX_VRAM_SUB_BG_128_C,			// サブ2DエンジンのBG
		GX_VRAM_SUB_BGEXTPLTT_NONE,		// サブ2DエンジンのBG拡張パレット

		GX_VRAM_OBJ_256_AB,				// メイン2DエンジンのOBJ
		GX_VRAM_OBJEXTPLTT_NONE,		// メイン2DエンジンのOBJ拡張パレット

		GX_VRAM_SUB_OBJ_16_I,			// サブ2DエンジンのOBJ
		GX_VRAM_SUB_OBJEXTPLTT_NONE,	// サブ2DエンジンのOBJ拡張パレット

		GX_VRAM_TEX_NONE,				// テクスチャイメージスロット
		GX_VRAM_TEXPLTT_NONE			// テクスチャパレットスロット
	};
	GF_Disp_SetBank( &tbl );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	引数の二乗を返す
 *
 *	@param	u32 num
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 CalcPow2( u32 num )
{
	return num * num;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	0に収束させる
 *
 *	@param	fx32* p_num
 *	@param	dec
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CalcZeroConverge( fx32* p_num, fx32 dec )
{
	if( *p_num == 0 ){ return; }

	if( MATH_IAbs(*p_num) < dec )
	{
		*p_num = 0;
	}
	else
	{
//		*p_num >>= 1;
		*p_num -= dec * ( *p_num > 0 ? 1 : -1 );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ジャンプ時のZ座標をフレームから計算する
 *
 *	@param	CATCH_POKE_PARAM* pCPokeParam	競技用ポケパラへのポインタ
 *	@param	NowFrame	アニメフレーム数
 *	@param	outScale	[OUT]拡大率
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 CalcJumpPosZ( CATCH_POKE_PARAM* pCPokeParam, u32 NowFrame, f32* outScale )
{
	u32 Duration;
	u32 Mul;
	fx32 fxResult = 0;
	f32 Scale = POKE_DEF_SCALE_F;

	GF_ASSERT( pCPokeParam );

	Duration = pCPokeParam->JumpDuration;
	Mul = CalcPow2( NowFrame - Duration ) - CalcPow2( Duration );

	if( Mul )
	{
		fx32 fxHigh = FX32_CONST( pCPokeParam->JumpHigh );

		if( fxHigh )
		{
			fxResult = fxHigh / 10 * Mul;

			// Clamp JUMP_Z_CLAMP_FX 以下にはならない
			fxResult = MATH_IMax( JUMP_Z_CLAMP_FX, fxResult );

			Scale -= FX_FX32_TO_F32( ( fxResult - FX32_CONST(4) ) / 100 );
		}
	}

#if 0
	HOSAKA_PRINT("Duration:%d ", Duration );
	HOSAKA_PRINT("High:0.%d ", pCPokeParam->JumpHigh );
	HOSAKA_PRINT("Scale:%f ", Scale );
	HOSAKA_PRINT("Result:%d \n", fxResult >> FX32_SHIFT );
#endif

	*outScale = Scale;

	return fxResult >> FX32_SHIFT;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ベクトルを0に収束させる
 *
 *	@param	VecFx32* pVec
 *	@param	decX
 *	@param	decY
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void VEC_ZeroConverge( VecFx32* pVec, fx32 decX, fx32 decY )
{
	CalcZeroConverge( &pVec->x, decX );
	CalcZeroConverge( &pVec->y, decY );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ベクトルのCLAMP
 *
 *	@param	VecFx32* vec
 *	@param	max
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void VEC_Clamp( VecFx32* vec, fx32 max )
{
	fx32 min = max*-1;

	if(vec->x > 0) {
		if(vec->x > max){ vec->x = max; }
	} else {
		if(vec->x < min){ vec->x = min; }
	}

	if(vec->y > 0) {
		if(vec->y > max){ vec->y = max; }
	} else {
		if(vec->y < min){ vec->y = min; }
	}
}


//----------------------------------------------------------------------------
/**
 *	@brief		レコード文字列展開
 *
 *	@param	work
 *	@param	inPoint
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetRecordStr( PKTHLN_PTR work, const int inPoint )
{
	PKTHLN_CATCH_PTR ptr;
	WORDSET *word;
	MSGDATA_MANAGER *msgman;
	STRBUF * str;
	int integer;

	ptr = PTFrame_GetEventWorkPtr(work);
    word = ptr->WordSet;
	msgman = ptr->MsgMan;
	integer = inPoint;	//整数部分

	GF_BGL_BmpWinDataFill( &ptr->Win, 0);

	WORDSET_RegisterNumber(word, 0, integer, 3, NUMBER_DISPTYPE_LEFT, NUMBER_CODETYPE_DEFAULT);

    str = MSGDAT_UTIL_AllocExpandString(word, msgman, msg_pkthln_new_record05, ptr->HeapID);

	GF_STR_PrintColor( &ptr->Win, FONT_TOUCH, str, 0, 0, MSG_NO_PUT, COL_N_WHITE, NULL );

	STRBUF_Delete( str );//<一括表示なので、メモリをここで消してもOK

	GF_BGL_BmpWinOn(&ptr->Win);
}

//-----------------------------------------------------------------------------
/**
 *	@brief	CATSシステム生成
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void OBJ_Create( PKTHLN_CATCH_PTR ptr )
{
	TCATS_RESOURCE_NUM_LIST crnl = { CHR_ID_MAX, PAL_ID_MAX, CEL_ID_MAX, ANM_ID_MAX, 0 };

	TCATS_OAM_INIT	coi = {
		0, 126,
		0, 32,
		1, 126,
		0, 32,
	};

	TCATS_CHAR_MANAGER_MAKE ccmm = {
		0,	// dummy
		1024*256,
		1024*16,
		GX_OBJVRAMMODE_CHAR_1D_256K,
		GX_OBJVRAMMODE_CHAR_1D_256K,
	};
	ccmm.num = OBJ_ID_MAX;

	ptr->csp = CATS_AllocMemory( ptr->HeapID );
	ptr->crp = CATS_ResourceCreate( ptr->csp );

	CATS_SystemInit( ptr->csp, &coi, &ccmm, 32 );
	CATS_ClactSetInit( ptr->csp, ptr->crp, CAP_ALL_NUM);
	CATS_ResourceManagerInit( ptr->csp, ptr->crp, &crnl );

	//サブサーフェースの距離を設定
	CLACT_U_SetSubSurfaceMatrix( CATS_EasyRenderGet( ptr->csp ), 0, OBJ_DISTANCE );

	// 共通リソース
	ptr->CmnResCntPtr = CmnRes_Init( ptr->HeapID,
			CMN_RES_ALL_BIT|CMN_RES_PEN_M_BIT|CMN_RES_CUR_BIT, NNS_G2D_VRAM_TYPE_2DMAIN );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	CATSシステム開放
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void OBJ_Delete( PKTHLN_CATCH_PTR ptr )
{
	PokeAct_Free( ptr->PokeActCntPtr );
	CmnRes_Free( ptr->CmnResCntPtr );
	CATS_ResourceDestructor_S( ptr->csp, ptr->crp );
	CATS_FreeMemory( ptr->csp );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	OBJアニメ停止
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void OBJ_Finish( PKTHLN_CATCH_PTR ptr )
{
	int i;

	PokeAct_AllAnmStop( ptr->PokeActCntPtr, 1 );

	CatchSub_Finish( ptr->cntSub );

	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		CATS_ObjectAutoAnimeSetCap( ptr->wkViewer.drawPoke[i].capSmoke, FALSE );
	}

	for( i=0; i<UFO_ID_MAX; i++ )
	{
		int k;
		UFO_DRAW* drawUfo = &ptr->wkViewer.drawUfo[i];

		for( k=0; k<UFO_CAP_NUM; k++ )
		{
			CATS_ObjectAutoAnimeSetCap( drawUfo->capUFO[k], FALSE );
			CATS_ObjectAutoAnimeSetCap( drawUfo->capShadow[k], FALSE );
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	OBJ用リソースのロード
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void OBJ_LoadRes( PKTHLN_CATCH_PTR ptr )
{
	int i;
	CATS_SYS_PTR csp = ptr->csp;
	CATS_RES_PTR crp = ptr->crp;
	NNS_G2D_VRAM_TYPE vram_type;

	GF_ASSERT(csp);
	GF_ASSERT(crp);

	//===========================================================
	// Main OBJ
	//===========================================================
	vram_type = NNS_G2D_VRAM_TYPE_2DMAIN;

	CATS_LoadResourceCharArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_main_lz_NCGR,
			TRUE, vram_type, CHR_ID_MAIN );

	CATS_LoadResourcePlttArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_main_NCLR,
			0, 2, vram_type, PAL_ID_MAIN );

	CATS_LoadResourceCellArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_main_lz_NCER,
			TRUE, CEL_ID_MAIN );

	CATS_LoadResourceCellAnmArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_main_lz_NANR,
			TRUE, ANM_ID_MAIN );
	//===========================================================
	// Sub OBJ
	//===========================================================
	vram_type = NNS_G2D_VRAM_TYPE_2DSUB;

	CATS_LoadResourceCharArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_sub_lz_NCGR,
			TRUE, vram_type, CHR_ID_SUB );

	CATS_LoadResourcePlttArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_sub_NCLR,
			0, 4, vram_type, PAL_ID_SUB );

	CATS_LoadResourceCellArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_sub_lz_NCER,
			TRUE, CEL_ID_SUB );

	CATS_LoadResourceCellAnmArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_sub_lz_NANR,
			TRUE, ANM_ID_SUB );

	//===========================================================
	// Common OBJ
	//===========================================================
	vram_type = NNS_G2D_VRAM_TYPE_2DMAIN;

	CATS_LoadResourceCharArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_cmn_lz_NCGR,
			TRUE, vram_type, CHR_ID_CMN_M );

	CATS_LoadResourcePlttArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_cmn_NCLR,
			0, 1, vram_type, PAL_ID_CMN_M );

	vram_type = NNS_G2D_VRAM_TYPE_2DSUB;

	CATS_LoadResourceCharArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_cmn_lz_NCGR,
			TRUE, vram_type, CHR_ID_CMN_S );

	CATS_LoadResourcePlttArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_cmn_NCLR,
			0, 1, vram_type, PAL_ID_CMN_S );

	CATS_LoadResourceCellArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_cmn_lz_NCER,
			TRUE, CEL_ID_CMN );

	CATS_LoadResourceCellAnmArc( csp, crp, ARC_PKTHEV_CATCH,
			NARC_pkthev_catch_catch_obj_cmn_lz_NANR,
			TRUE, ANM_ID_CMN );
}

static CATS_ACT_PTR OBJ_AddCapCmn( CATS_SYS_PTR csp, CATS_RES_PTR crp, s16 px, s16 py, u16 anime, u16 pri, BOOL bMainLCD )
{
	TCATS_OBJECT_ADD_PARAM_S prm_s = {
		0, 0, 0,
		0, 0, TCATS_ADD_S_PAL_AUTO, NNS_G2D_VRAM_TYPE_2DSUB,
		{ CHR_ID_CMN_S, PAL_ID_CMN_S, CEL_ID_CMN, ANM_ID_CMN },
		1, 0,
	};

	TCATS_OBJECT_ADD_PARAM_S prm_m = {
		0, 0, 0,
		0, 0, TCATS_ADD_S_PAL_AUTO, NNS_G2D_VRAM_TYPE_2DMAIN,
		{ CHR_ID_CMN_M, PAL_ID_CMN_M, CEL_ID_CMN, ANM_ID_CMN },
		1, 0,
	};

	TCATS_OBJECT_ADD_PARAM_S* prm;
	CATS_ACT_PTR cap;

	prm = ( bMainLCD ) ? &prm_m : &prm_s;

	GF_ASSERT(csp);
	GF_ASSERT(crp);

	prm->x = px;
	prm->y = py;
	prm->anm = anime;
	prm->pri = pri;

	cap = CATS_ObjectAdd_S_SubDistance( csp, crp, prm, OBJ_DISTANCE );
	CATS_ObjectAffineSetCap( cap, CLACT_AFFINE_DOUBLE );
	CATS_ObjectAutoAnimeSetCap( cap, TRUE );
	CATS_ObjectEnableCap( cap, CATS_ENABLE_FALSE );

	return cap;
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	CATS_SYS_PTR csp
 *	@param	crp
 *	@param	px
 *	@param	py
 *	@param	anime
 *	@param	pri
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static CATS_ACT_PTR OBJ_AddCapMain( CATS_SYS_PTR csp, CATS_RES_PTR crp, s16 px, s16 py, u16 anime, u16 pri )
{
	TCATS_OBJECT_ADD_PARAM_S prm = {
		0, 0, 0,
		0, 0, TCATS_ADD_S_PAL_AUTO, NNS_G2D_VRAM_TYPE_2DMAIN,
		{ CHR_ID_MAIN, PAL_ID_MAIN, CEL_ID_MAIN, ANM_ID_MAIN },
		1, 0,
	};

	CATS_ACT_PTR cap;

	GF_ASSERT(csp);
	GF_ASSERT(crp);

	prm.x = px;
	prm.y = py;
	prm.anm = anime;
	prm.pri = pri;

	cap = CATS_ObjectAdd_S_SubDistance( csp, crp, &prm, OBJ_DISTANCE );
	CATS_ObjectAutoAnimeSetCap( cap, TRUE );
	CATS_ObjectEnableCap( cap, CATS_ENABLE_FALSE );

	return cap;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	BG初期化
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void BG_Init( PKTHLN_CATCH_PTR ptr )
{
	GF_BGL_INI* bgl = ptr->bgl;
	HEAPID HeapID = ptr->HeapID;

	{	/* BG SYSTEM */
		GF_BGL_SYS_HEADER BGsys_data = {
			GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BGMODE_0, GX_BG0_AS_2D,
		};
		GF_BGL_InitBG( &BGsys_data );
	}

	{
		int i;
		GF_BGL_BGCNT_HEADER bg_data[ BG_USE_NUM ] = {
			// -- MAIN --
			{	// BG_0 海
				0,0,0x800,0,GF_BGL_SCRSIZ_256x256,GX_BG_COLORMODE_16,
				GX_BG_SCRBASE_0x0000,GX_BG_CHARBASE_0x04000,GX_BG_EXTPLTT_01,
				3,0,0,FALSE
			},
			{	// BG_1 土台
				0,0,0x800,0,GF_BGL_SCRSIZ_256x256,GX_BG_COLORMODE_16,
				GX_BG_SCRBASE_0x0800,GX_BG_CHARBASE_0x08000,GX_BG_EXTPLTT_01,
				1,0,0,FALSE
			},
			{	// BG_2 リザルト
				0,0,0x800,0,GF_BGL_SCRSIZ_256x256,GX_BG_COLORMODE_16,
				GX_BG_SCRBASE_0x1000,GX_BG_CHARBASE_0x0c000,GX_BG_EXTPLTT_01,
				0,0,0,FALSE
			},
			// -- SUB --
			{	// BG_0 海
				0,0,0x800,0,GF_BGL_SCRSIZ_256x256,GX_BG_COLORMODE_16,
				GX_BG_SCRBASE_0x0000,GX_BG_CHARBASE_0x04000,GX_BG_EXTPLTT_01,
				3,0,0,FALSE
			},
			{	// BG_1 ウィンドウ
				0,0,0x800,0,GF_BGL_SCRSIZ_256x256,GX_BG_COLORMODE_16,
				GX_BG_SCRBASE_0x0800,GX_BG_CHARBASE_0x08000,GX_BG_EXTPLTT_01,
				2,0,0,FALSE
			},
			{	// BG_2 スコア
				0,0,0x800,0,GF_BGL_SCRSIZ_256x256,GX_BG_COLORMODE_16,
				GX_BG_SCRBASE_0x1000,GX_BG_CHARBASE_0x10000,GX_BG_EXTPLTT_01,
				1,0,0,FALSE
			},
			{	// BG_3 テキスト
				0,0,0x800,0,GF_BGL_SCRSIZ_256x256,GX_BG_COLORMODE_16,
				GX_BG_SCRBASE_0x1800,GX_BG_CHARBASE_0x18000,GX_BG_EXTPLTT_01,
				0,0,0,FALSE
			},
		};

		for( i=0; i<BG_USE_NUM; i++ )
		{
			GF_BGL_BGControlSet( bgl, c_BG_UseList[i], &(bg_data[i]), GF_BGL_MODE_TEXT );
			GF_BGL_ScrClear( bgl, c_BG_UseList[i] );
			GF_BGL_ClearCharSet( c_BG_UseList[i], 32, 0, HeapID );
		}
	}

	ptr->MsgMan = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG, NARC_msg_pokethlon_dat, ptr->HeapID );
	ptr->WordSet = WORDSET_Create( ptr->HeapID );

	//タッチフォントロード
	FontProc_LoadFont(FONT_TOUCH, ptr->HeapID);

	//レコードＢＧ非表示
	GF_Disp_GX_VisibleControl( BG_FRM_M_RSLT_MASK, VISIBLE_OFF );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	BG削除
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void BG_Delete( PKTHLN_CATCH_PTR ptr )
{
	int i;

	// BMPWIN削除
	GF_BGL_BmpWinDel( &ptr->Win );

	WORDSET_Delete( ptr->WordSet );
	MSGMAN_Delete( ptr->MsgMan );

	// BGコントーラー開放
	for( i=0; i<BG_USE_NUM; i++ )
	{
		GF_BGL_BGControlExit( ptr->bgl, c_BG_UseList[i] );
	}

	//タッチフォントアンロード
	FontProc_UnloadFont(FONT_TOUCH);

	// BGL開放
	sys_FreeMemoryEz( ptr->bgl );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	BGリソースロード
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void BG_LoadRes( PKTHLN_CATCH_PTR ptr )
{
	// ++ 下画面 (Main) ++
	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_trans_lz_NCGR,
						ptr->bgl, BG_FRM_M_TRANS, 0, 0, TRUE, ptr->HeapID);

	ArcUtil_BgCharSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_main_lz_NCGR,
						ptr->bgl, BG_FRM_M_LAND, 0, 0, TRUE, ptr->HeapID);

	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_trans01_lz_NSCR,
						ptr->bgl, BG_FRM_M_TRANS, 0, 0, TRUE, ptr->HeapID);

	ArcUtil_ScrnSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_main01_lz_NSCR,
						ptr->bgl, BG_FRM_M_LAND, 0, 0, TRUE, ptr->HeapID);

	//パレット
	ArcUtil_PalSet( ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_main_NCLR,
						PALTYPE_MAIN_BG, 0, 0, ptr->HeapID );

	// 揺らすBGはズラして読み込む
	GF_BGL_ScrollReq( ptr->bgl, BG_FRM_M_LAND, GF_BGL_SCROLL_Y_INC, SCR_DEF_OFS );

	//システム用フォントパレット転送
	SystemFontPaletteLoad(PALTYPE_MAIN_BG, MAIN_FONT_PAL*0x20, ptr->HeapID);

	// ++ 上画面 (Sub) ++

	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_trans_lz_NCGR,
						ptr->bgl, BG_FRM_S_TRANS, 0, 0, TRUE, ptr->HeapID);

	ArcUtil_BgCharSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_sub02_lz_NCGR,
						ptr->bgl, BG_FRM_S_WIN, 0, 0, TRUE, ptr->HeapID);

	ArcUtil_BgCharSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_sub02_lz_NCGR,
						ptr->bgl, BG_FRM_S_SCORE, 0, 0, TRUE, ptr->HeapID);

	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_trans01_lz_NSCR,
						ptr->bgl, BG_FRM_S_TRANS, 0, 0, TRUE, ptr->HeapID);

	ArcUtil_ScrnSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_sub02_lz_NSCR,
						ptr->bgl, BG_FRM_S_WIN, 0, 0, TRUE, ptr->HeapID);

	ArcUtil_ScrnSet(ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_sub03_lz_NSCR,
						ptr->bgl, BG_FRM_S_SCORE, 0, 0, TRUE, ptr->HeapID);

	//パレット
	ArcUtil_PalSet( ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_sub_NCLR,
						PALTYPE_SUB_BG, 0, 0, ptr->HeapID );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	BGアニメ処理
 *
 *	@param	BG_TRANS_WORK* wk
 *	@param	ini
 *	@param	HEAPID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void BG_TransAnimeProc( BG_TRANS_WORK* wk, GF_BGL_INI* ini, HEAPID HeapID )
{
	GF_ASSERT(wk);
	GF_ASSERT(ini);

	if( ++wk->Counter >= BG_TRANS_ANIME_SYNC )
	{
//		HOSAKA_PRINT("trans bg anime \n");

		ArcUtil_ScrnSet( ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_trans01_lz_NSCR + wk->Offset,
				ini, BG_FRM_M_TRANS, 0, 0, TRUE, HeapID );

		ArcUtil_ScrnSet( ARC_PKTHEV_CATCH, NARC_pkthev_catch_catch_bg_trans01_lz_NSCR + wk->Offset,
				ini, BG_FRM_S_TRANS, 0, 0, TRUE, HeapID );


		wk->Offset = (wk->Offset+1) % BG_TRANS_ANIME_NUM;

		wk->Counter = 0;
	}
}


//-----------------------------------------------------------------------------
/**
 *	@brief	通信データのやりくり
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CommMain( PKTHLN_PTR work )
{
	int i;
	PKTHLN_CATCH_PTR ptr;
	COMM_EVENT_COMMON_DATA* data;

	ptr = PTFrame_GetEventWorkPtr(work);
	data = PTFrame_GetEvtComCmnData(work);

	// 親処理
	if( PTFrameGetCurrentID(work) == COMM_PARENT_ID )
	{
		int GameSec = 0;
		CATCH_COMM_PARENT_PTR parent;

		parent = PKTHLN_CommPack_GetData(&data->SendShareData);

		// 終了フラグが立っていれば処理を打ち切る
		if( parent->EndFlag )
		{
			// 通信データセット
			TeamCnt_SetCommData( &ptr->wkServer, work );
			return;
		}

		// 時間経過
		if( ptr->wkServer.GameTimer > 0 )
		{
#ifdef PM_DEBUG
		if( DebugPkthlnWk.TimeInfinity == 0 )
#endif
			{
				ptr->wkServer.GameTimer--;
			}

			GameSec = ( ptr->wkServer.GameTimer + 30 ) / GAME_FPS;

#ifdef PM_DEBUG
			if( parent->GameSec != GameSec )
			{
				HOSAKA_PRINT( "GameSec:%d \n", GameSec );
			}
#endif
			parent->GameSec = GameSec;
		}

		//親データは直接レシーバにセット
		{
			CATCH_COMM_CHILD_PTR child;
			CATCH_COMM_CHILD_PTR child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[0]);
			child = PKTHLN_CommPack_GetData(&data->SendData);
			(*child_rec) = (*child);
		}

		// 親機 レシーバー集計
		for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
		{
			CATCH_COMM_CHILD_PTR child_rec;
			TEAM_DATA* TeamData;
			TP_STATE_CATCH* TpState;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[i]);
			TeamData = &ptr->wkServer.TeamData[i];
			TpState = &TeamData->TpState;

			// タッチ状況を整理
			if( child_rec->TouchVaild )
			{
				if( TpState->Trg && TpState->Cont )
				{
					// トリガフラグOFF
					TpState->Trg = FALSE;
				}
				else
				if( TpState->Trg == FALSE && TpState->Cont == FALSE )
				{
					TpState->Trg = TRUE;
					TpState->Cont = TRUE;
				}

				TeamData->TouchPos.X = child_rec->TpX;
				TeamData->TouchPos.Y = child_rec->TpY;

//				HOSAKA_PRINT("[%d] TpCont{%d,%d} cnt:%d \n",i,child_rec->TpX,child_rec->TpY,TpState->ContCounter);
				TpState->ContCounter++;
			}
			else
			{
				TeamData->TpState.ReleaseCount = TpState->ContCounter;
				TpState->ContCounter = 0;
				TpState->Trg = FALSE;
				TpState->Cont = FALSE;
			}
		}

#ifdef PM_DEBUG
		if( DebugPkthlnWk.AI_Stop == 0 )
#endif
		{
			// AI処理
			CatchAICnt_Proc( ptr->cntAI );
		}

#ifdef PM_DEBUG
		// 時間が無限のときはスタートで次の難易度へ
		if( DebugPkthlnWk.TimeInfinity && (sys.trg & PAD_BUTTON_START) )
		{
			UFO_CNT_DATA* cntUfo = &ptr->wkServer.UfoCntData;
			cntUfo->CreateLevel =  ( cntUfo->CreateLevel + 1 ) % UFO_LEVEL_MAX;
			HOSAKA_PRINT("debug set UFO CreateLevel=%d \n", cntUfo->CreateLevel );
		}
#endif

		// UFO処理
		UFO_CNT_Calc( &ptr->wkServer.UfoCntData, data, GameSec );
		// ポケモン処理
		TeamCnt_Calc( ptr->wkServer.TeamData, work );

		// 終了判定
		if( ptr->wkServer.GameTimer <= 0 )
		{
			parent->EndFlag = 1;
		}

		// 通信データセット
		TeamCnt_SetCommData( &ptr->wkServer, work );

	} // 親機処理終了
}

//-----------------------------------------------------------------------------
/**
 *	@brief	主処理
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL MainProc( PKTHLN_PTR work )
{
	PKTHLN_CATCH_PTR ptr;
	COMM_EVENT_COMMON_DATA* data;
	CATCH_COMM_CHILD_PTR child_data;
	CATCH_COMM_PARENT_PTR parent;

	ptr = PTFrame_GetEventWorkPtr(work);
	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	child_data = PKTHLN_CommPack_GetData(&data->SendData);

#ifdef PM_DEBUG
	// Xで強制終了
	if( sys.trg & PAD_BUTTON_X )
	{
		parent->EndFlag = 1;
	}
#endif

	if( parent->EndFlag == 1 )
	{
		// OBJアニメ停止
		OBJ_Finish( ptr );
		PTFrame_StopPosMarker( work );

		RecCallBack( work );
		return TRUE;
	}

	if( GF_TP_GetTrg() )
	{
		// AP:タッチ回数
		PTFrame_AddActionPoint( work, PTFrameGetCurrentID(work), ENTRY_MAX, ADD_TYPE_TOUCH, 1 );
	}

	if( GF_TP_GetCont() )
	{
		// 通信データに座標をセット
		child_data->TpX = sys.tp_x;
		child_data->TpY = sys.tp_y;
		child_data->TouchVaild = TRUE;
//		HOSAKA_PRINT("[%d]Send Touch \n", PTFrameGetCurrentID(work) );
	}
	else
	{
		child_data->TouchVaild = FALSE;
	}

	// 描画処理
	COMM_VIEWER_Draw( &ptr->wkViewer, work );

	return FALSE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	コンバートデータを取得
 *
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void SetCatchPokeParam( PKTHLN_PTR work )
{
	int i, j;
	CATCH_CONV_PARAM ConvData;

	ArchiveDataLoad( &ConvData, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_catch_bin );

	for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
	{
		for( j=0; j<ENTRY_MAX; j++ )
		{
			const POKE_SPEC* pPokeSpec;
			CATCH_POKE_PARAM* pCPokeParam;

			pPokeSpec = PTFrame_GetPokeSpec( work, i, j );
			pCPokeParam = GetCatchPokeParam( work, i, j );

			GF_ASSERT( pPokeSpec->Jump < CATCH_CONV_PARAM_MAX );
			GF_ASSERT( pPokeSpec->Power < CATCH_CONV_PARAM_MAX );
			GF_ASSERT( pPokeSpec->Speed < CATCH_CONV_PARAM_MAX );

			pCPokeParam->JumpLevel = pPokeSpec->Jump;
			pCPokeParam->JumpDuration = ConvData.JumpDuration[ pPokeSpec->Jump ];
			pCPokeParam->JumpHigh = ConvData.JumpHigh[ pPokeSpec->Jump ];
			pCPokeParam->fxPower = FX32_CONST( ConvData.Power[ pPokeSpec->Power ] ) / 10; // 1/10にして使用
			pCPokeParam->fxMove = FX32_CONST( ConvData.Speed[ pPokeSpec->Speed ] ) / 10; // 1/10にして使用

			HOSAKA_PRINT( "[%d,%d] JumpDuration:%d JumpHigh:%d Move:%03f Power:%03f \n",
				i, j,
				pCPokeParam->JumpDuration, pCPokeParam->JumpHigh,
				FX_FX32_TO_F32(pCPokeParam->fxMove),
				FX_FX32_TO_F32(pCPokeParam->fxPower) );
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	パラメータ取得
 *
 *	@param	PKTHLN_PTR work
 *	@param	NetID
 *	@param	PokeIdx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static CATCH_POKE_PARAM* GetCatchPokeParam( PKTHLN_PTR work, u8 NetID, u8 PokeIdx )
{
	CATCH_POKE_PARAM* pRet;
	PKTHLN_CATCH_PTR ptr = PTFrame_GetEventWorkPtr(work);

	GF_ASSERT(ptr);
	GF_ASSERT( NetID < ENTRY_MEMBER_NUM_MAX );
	GF_ASSERT( PokeIdx < ENTRY_MAX );

	pRet = &ptr->CatchPokeParam[ NetID * ENTRY_MAX + PokeIdx ];

	GF_ASSERT( pRet );

	return pRet;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	パラメータからジャンプフレーム数を取得
 *
 *	@param	const CATCH_POKE_PARAM* pCPokeParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u16 GetJumpFrame( const CATCH_POKE_PARAM* pCPokeParam )
{
	return pCPokeParam->JumpDuration * 2;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO_DATAから得点を計算
 *
 *	@param	UFO_DATA* ufo
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u8 UfoStateToScore( UFO_DATA* ufo )
{
	switch( ufo->State )
	{
		case UFO_ST_POINT_1 : return 1;
		case UFO_ST_POINT_2 : return 2;
		case UFO_ST_POINT_3 : return 3;
		case UFO_ST_POINT_5 : return 5;
		default : GF_ASSERT(0);
	}

	return 0;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケアクター 生成
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void TeamCnt_Create( PKTHLN_CATCH_PTR ptr )
{
	// ワーク生成
	ptr->PokeActCntPtr = PokeAct_Init(
			ptr->HeapID, ACT_POKE_MAX, PRI_POKE,
			ptr->CmnResCntPtr, CATS_GetClactSetPtr(ptr->crp) );

	PokeAct_SetBigPokeChinkFlag( ptr->PokeActCntPtr );

	// ポケアクター セットアップ
	{
		int i;
		MONS_INFO info[ ACT_POKE_MAX ];
		PCLACT_SET_PARAM param = {0};
		PKTHLN_PTR work = ptr->PkthlnWork;

		for( i=0; i<ACT_POKE_MAX; i++ )
		{
			const PKTHPOKE_PARAM* pp;

			PTFrame_SetMonsInfo( work, i/ENTRY_MAX, i%ENTRY_MAX, &info[i] );
			pp = PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX);
			param.ShadowPos[i] = PTFrame_GetPokeShdwPosType( pp );
		}

		param.BGPriority = 1;
		param.ResVramType = NNS_G2D_VRAM_TYPE_2DMAIN;
		param.DrawArea = NNS_G2D_VRAM_TYPE_2DMAIN;

		PokeAct_SetPokeActor( ptr->PokeActCntPtr, ACT_POKE_MAX, info, &param, 0, 0 );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケアクター 初期化
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void TeamCnt_Init( PKTHLN_CATCH_PTR ptr )
{
	int i;
	EVT_HIT_DATA hit_data = {0};
	PEN_POS pen_pos[ENTRY_MAX];
	PKTHLN_PTR work;

	// 当たり判定データをロード
	ArchiveDataLoad(hit_data.Data, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_catch_hit_bin);

	GF_ASSERT(ptr);
	GF_ASSERT( ptr->PkthlnWork );
	GF_ASSERT( hit_data.Data );

	work = ptr->PkthlnWork;

	// コンバートデータを取得
	SetCatchPokeParam( work );

	// チームデータの初期化
	for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
	{
		ptr->wkServer.TeamData[i].NetID = i;
	}

	//ポケセルアクター関連初期化
	for (i=0;i<ACT_POKE_MAX;i++)
	{
		CATCH_POKE* pCPoke = &ptr->wkServer.TeamData[ i/ENTRY_MAX ].CatchPoke[ i%ENTRY_MAX ];
		POKE_ACT_PTR poke_ptr;

		poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);

		PokeAct_DispCnt(poke_ptr, 1);	//表示

		//あたり判定データセット
		{
			HIT_TYPE hit_type;
			hit_type = PTFrame_GetPokeHitType( PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX) );
			PokeAct_SetHitData(poke_ptr, hit_data.Data[hit_type-1].Ofs, hit_data.Data[hit_type-1].Range);
		}

		//ポケモン初期位置
		{
			const MONS_INFO *info;
			POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);
			PCLACT_PTR	pclact_ptr = PokeAct_GetPclActPtr(poke_ptr);

			info = PCLACT_GetMonsInfo(pclact_ptr);

			// アフィン設定 中心座標を足元に
			Poke_SetAffineVec( poke_ptr, FALSE );
			PokeAct_SetScale( poke_ptr, POKE_DEF_SCALE_F, POKE_DEF_SCALE_F );

			//テーブルで位置決定
			{
				int sx,sy;
				int tx,ty;
				int range;

				//影の位置
				sx = g_PokeInitPos[i/ENTRY_MAX][i%ENTRY_MAX].X;
				sy = g_PokeInitPos[i/ENTRY_MAX][i%ENTRY_MAX].Y;

				//向きセット
				PokeAct_SetDir(poke_ptr, POKE_DIR_DOWN);
				//アクター位置セット
				PokeAct_SetPosShadow(poke_ptr, sx, sy);

				//タッチ半径セット
				range = PTFrame_GetPokeTouchRange();
				PokeAct_SetTouchRange(poke_ptr, range);

				//タッチ中心座標取得
				PokeAct_GetTouchPosByShadowPos(poke_ptr, sx, sy, &tx, &ty);

				//データ保持
				pCPoke->work = work;
				pCPoke->ID = i;
				pCPoke->NetID = i / ENTRY_MAX;
				pCPoke->PokeID = i % ENTRY_MAX;
				pCPoke->PokeActPtr = poke_ptr;
				pCPoke->CellType = info->CellType;
				pCPoke->cpp = GetCatchPokeParam( work, i/ENTRY_MAX, i%ENTRY_MAX );
				pCPoke->State = POKE_ST_ALIVE;
				pCPoke->Dir = POKE_DIR_DOWN;
				pCPoke->NowPos.x = tx * FX32_ONE;
				pCPoke->NowPos.y = ty * FX32_ONE;
				pCPoke->LastPos.x = tx * FX32_ONE;
				pCPoke->LastPos.y = ty * FX32_ONE;

				if (i/ENTRY_MAX == PTFrameGetCurrentID(work))
				{
					CLACT_WORK_PTR act_ptr;

					pen_pos[i%ENTRY_MAX].X = sx;
					pen_pos[i%ENTRY_MAX].Y = sy;

					// ▼マーカーセット
					act_ptr = PTFrame_SetPosMarker( work, poke_ptr, ptr->CmnResCntPtr, CATS_GetClactSetPtr(ptr->crp), 1 );
					CLACT_DrawPriorityChg( act_ptr, PRI_POS_MARKER );

					// 自分のポケは表示優先度が高い
					PokeAct_SetPriority(poke_ptr, PRI_POKE_MINE);
				}
				else
				{
					PokeAct_SetPriority(poke_ptr, PRI_POKE);
				}

				//親のとき、初回送信データを作成
				if (PTFrameGetCurrentID(work) == COMM_PARENT_ID) {
					COMM_EVENT_COMMON_DATA *data;
					CATCH_COMM_PARENT_PTR parent;

					data = PTFrame_GetEvtComCmnData(work);
					parent = PKTHLN_CommPack_GetData(&data->SendShareData);

					// データ格納
					parent->PokeX[i] = tx;
					parent->PokeY[i] = ty;
				}

				HOSAKA_PRINT("[%d] pos{%d,%d} range:%d \n", i, sx, sy, range );
			}
		} //ポケモン初期位置
	}	//end for

	// ペン表示
	PTFrame_SetPenByClSet( work, 0, ptr->CmnResCntPtr, CATS_GetClactSetPtr(ptr->crp), NNS_G2D_VRAM_TYPE_2DMAIN, ENTRY_MAX, pen_pos );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チームコントローラー 当たり判定
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void TeamCnt_CalcPokeCollision( PKTHLN_PTR work )
{
	int i, j;
	PKTHLN_CATCH_PTR ptr;
	u8 (*Invalid)[ACT_POKE_MAX]; ///< 二次元配列へのポインタ
	BOOL bHit = FALSE;

	ptr = PTFrame_GetEventWorkPtr(work);
	Invalid = ptr->wkServer.PokeInvalidCollision; ///< 処理フラグ

	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		CATCH_POKE* pCPoke = &ptr->wkServer.TeamData[i/ENTRY_MAX].CatchPoke[i%ENTRY_MAX];

		for( j = i+1; j<ACT_POKE_MAX; j++ )
		{
			CATCH_POKE* pTar;

			pTar = &ptr->wkServer.TeamData[j/ENTRY_MAX].CatchPoke[j%ENTRY_MAX];

			if( Poke_IsHitActive( pCPoke ) && Poke_IsHitActive( pTar ) &&
				Poke_CheckCircle( pCPoke, pTar ) && !Invalid[i][j] )
			{
				fx32 fxPower;
				VecFx32 Intersect = {0};	///< 2点の中心点で定義される単位ベクトル

				Invalid[i][j] = Invalid[j][i] = 1;

				VEC_Subtract( &pCPoke->NowPos, &pTar->NowPos, &Intersect );
				VEC_Normalize(&Intersect, &Intersect);

				// 相手のパワーと自分のサイズを見て吹っ飛ぶ(小さいと1.2倍吹っ飛ぶ)
				fxPower = pTar->cpp->fxPower;
				if( pCPoke->CellType == 0 ){ fxPower = fxPower * 6 / 5; }
				VEC_MultAdd( fxPower, &Intersect, &pCPoke->NormDirVec, &pCPoke->PushVec );

				// 相手側
				fxPower = pCPoke->cpp->fxPower;
				if( pTar->CellType == 0 ){ fxPower = fxPower * 6 / 5; }
				VEC_MultAdd( fxPower, &Intersect, &pTar->NormDirVec, &pTar->PushVec );
				pTar->PushVec.x *= -1;
				pTar->PushVec.y *= -1;

				// 速度規制
				VEC_Clamp( &pCPoke->PushVec, POKE_PUSH_VEC_MAX_FX );
				VEC_Clamp( &pTar->PushVec, POKE_PUSH_VEC_MAX_FX );

				// 目的地変更
//				VEC_Add(&pCPoke->PushVec, &pCPoke->LastPos, &pCPoke->LastPos );
//				VEC_Add(&pTar->PushVec, &pTar->LastPos, &pTar->LastPos );

				// 衝突されたポケモンの向きを変更
				pTar->Dir = Poke_GetDir( &Intersect );
				pTar->bPush = 1;
				pCPoke->bPush = 1;
				// ※相手側は吹っ飛ばない
//				pTar->PushVec = (VecFx32){0,0,0,};

#ifdef DEBUG_PRINT_PUSH
				HOSAKA_PRINT( "Push [%d]%f->{%f,%f} [%d]%f->{%f,%f}\n",
						i, FX_FX32_TO_F32(pTar->cpp->fxPower),
						FX_FX32_TO_F32(pCPoke->PushVec.x) ,FX_FX32_TO_F32(pCPoke->PushVec.y),
						j, FX_FX32_TO_F32(pCPoke->cpp->fxPower),
						FX_FX32_TO_F32(pTar->PushVec.x) ,FX_FX32_TO_F32(pTar->PushVec.y) );
#endif

			}
			else
			{
				Invalid[i][j] = Invalid[j][i] = 0;	// 処理フラグを折る
			}
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チームコントローラー 主処理
 *
 *	@param	TEAM_DATA* pTeamDataHead
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void TeamCnt_Calc( TEAM_DATA* pTeamDataHead, PKTHLN_PTR work )
{
	COMM_EVENT_COMMON_DATA* data;
	CATCH_COMM_PARENT_PTR parent;
	int i,j;

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->SendShareData);

	for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
	{
		TEAM_DATA* pTeamData = &pTeamDataHead[i];
		TP_STATE_CATCH* TpState = &pTeamData->TpState;

		pTeamData->CatchPoke[ TpState->PokeIdx ].bSetPos = 0;

		// TRG判定
		if( TpState->Trg )
		{
			u8 touchIdx = CheckPokeTouch( pTeamData->CatchPoke, pTeamData->TouchPos.X, pTeamData->TouchPos.Y );
			if( touchIdx != ACT_POKE_MAX )
			{
				// ターゲットを特定
				TpState->bLockOn = 1;
				TpState->PokeIdx = touchIdx;

				HOSAKA_PRINT("[%d,%d] Touch Trg \n",  pTeamData->NetID, touchIdx );
			}
		}
		// CONT判定
		else if( TpState->Cont )
		{
			if( TpState->bLockOn == 1 )
			{
				CATCH_POKE* pCPoke = &pTeamData->CatchPoke[ TpState->PokeIdx ];

				s16 now_x = pCPoke->NowPos.x >> FX32_SHIFT;
				s16 now_y = pCPoke->NowPos.y >> FX32_SHIFT;

				// 落下したらロックを切る
				if( pCPoke->State == POKE_ST_FALL )
				{
					TpState->bLockOn = 0;
				}
				else
				// アソビ
				if( MATH_IAbs( pTeamData->TouchPos.X - now_x ) > POKE_TOUCH_PLAY ||
					MATH_IAbs( pTeamData->TouchPos.Y - now_y ) > POKE_TOUCH_PLAY )
				{
					// 移動先更新
					Poke_SetLastPos( pCPoke, &pTeamData->TouchPos );

					// 設定した座標が場外か判定
					pCPoke->bOwn = ( Poke_CheckFall( pCPoke, pCPoke->LastPos.x, pCPoke->LastPos.y ) );
				}

			}
		}
		// リリース
		else
		{
			// ロックオン中
			if( TpState->bLockOn == 1 )
			{
				CATCH_POKE* pCPoke = &pTeamData->CatchPoke[ TpState->PokeIdx ];
				u8 touchIdx = CheckPokeTouch( pTeamData->CatchPoke, pTeamData->TouchPos.X, pTeamData->TouchPos.Y );

				// ジャンプ判定
				if( (pCPoke->State == POKE_ST_ALIVE) && (touchIdx == TpState->PokeIdx) )
				{
					HOSAKA_PRINT("ReleaseCount:%d \n",TpState->ReleaseCount);

					if( TpState->ReleaseCount <= JUMP_CHECK_SYNC )
					{
						// ジャンプ処理開始
						Poke_StartJump( pCPoke );
					}
				}
			}

			TpState->bLockOn = 0;
		}

		// ポケモン処理
		for( j=0; j<ENTRY_MAX; j++ )
		{
			Poke_Calc( &pTeamData->CatchPoke[j], work );
		}
	}

	// ポケモンヒット処理
	TeamCnt_CalcPokeCollision( work );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チームコントローラー 通信データセット
 *
 *	@param	SERVER_WORK* pServer
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void TeamCnt_SetCommData( SERVER_WORK* pServer, PKTHLN_PTR work )
{
	int i;
	COMM_EVENT_COMMON_DATA* data;
	CATCH_COMM_PARENT_PTR parent;

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->SendShareData);

	parent->ScoreHeader = (parent->ScoreHeader + 1 ) % ENTRY_MEMBER_NUM_MAX;
	parent->Score = ( pServer->TeamData[ parent->ScoreHeader ].Score ) & 0x7f ; // 7 bit mask

	parent->JumpBit = 0;
	parent->DirBit = 0;
	parent->FallBit = 0;
	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		CATCH_POKE* pCPoke = &pServer->TeamData[i/ENTRY_MAX].CatchPoke[i%ENTRY_MAX];
		s16 px, py;
		int sx, sy;

		px = pCPoke->NowPos.x >> FX32_SHIFT;
		py = pCPoke->NowPos.y >> FX32_SHIFT;

		// タッチ座標から影座標を算出
		PokeAct_GetShadowPosByTouchPos( pCPoke->PokeActPtr, px, py, &sx, &sy );

		// 移動
		parent->PokeX[i] = MATH_CLAMP( sx, 0, 255 );
		parent->PokeY[i] = MATH_CLAMP( sy, 0, 255 );

		// ジャンプデータ
		if( pCPoke->JumpSendFrame > 0 )
		{
			parent->JumpBit |= (1<<i);
			pCPoke->JumpSendFrame--;
		}

		// 落下データ
		if( pCPoke->State == POKE_ST_FALL )
		{
			parent->FallBit |= (1<<i);
		}

		// 方向データセット
		parent->DirBit += (pCPoke->Dir-1) << i*2;
//		HOSAKA_PRINT("[%d] ", pCPoke->Dir );
	}

#ifdef PM_DEBUG
//	HOSAKA_PRINT("set DirBit : 0x%x \n", parent->DirBit );
//	if( parent->FallBit ){ HOSAKA_PRINT("FallBit : 0x%x \n", parent->FallBit ); }
#endif

}


//-----------------------------------------------------------------------------
/**
 *	@brief	UFO初期化
 *
 *	@param	UFO_DATA* ufo
 *	@param	SpeedY
 *	@param	ID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_Init( UFO_DATA* ufo, u8 SpeedY, u8 ID )
{
	ufo->bAlive = TRUE;
	ufo->PosX = GX_LCD_SIZE_X / 2;
	ufo->PosY = 0;
	ufo->PosX = 0;
	ufo->State = UFO_ST_NORMAL;
	ufo->ID = ID;
#ifdef DEBUG_UFO_HOOK
	ufo->Vec = debug_ufo_vec;
#else
	ufo->Vec = gf_mtRand() % 15;
#endif
	ufo->ScoreTimer = 0;
	ufo->SpeedY = SpeedY;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO 消去
 *
 *	@param	UFO_DATA* ufo
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_Delete( UFO_DATA* ufo )
{
	ufo->bAlive = FALSE;
	ufo->State = UFO_ST_NONE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFOとポケモンの当たり判定(影同士)
 *
 *	@param	UFO_DATA* ufo
 *	@param	TeamDataHead
 *	@param	outPoke [out]
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL UFO_CheckHitPoke( UFO_DATA* ufo, TEAM_DATA* TeamDataHead, UFO_GET_POKE* outPoke )
{
	int i;
	s16 ufo_y;

	ufo_y = ufo->PosY;

	// 上画面の間は判定しない
	if( ufo_y < GX_LCD_SIZE_Y + DISP_DISTANCE ){ return FALSE; }

	// 座標調整
	ufo_y -= GX_LCD_SIZE_Y + DISP_DISTANCE;

	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		CATCH_POKE* pCPoke;
		VecFx32 vec = {0};
		fx32 len;
		fx32 range;
		int r1, r2;
		int poke_x, poke_y;

		pCPoke = &TeamDataHead[i/ENTRY_MAX].CatchPoke[i%ENTRY_MAX];

		// ジャンプ状態でなければ判定しない
		if( pCPoke->State != POKE_ST_JUMP ){ continue; }

		// タッチ座標から影座標を算出
		PokeAct_GetShadowPosByTouchPos(pCPoke->PokeActPtr,
				pCPoke->NowPos.x>>FX32_SHIFT, pCPoke->NowPos.y>>FX32_SHIFT,
				&poke_x, &poke_y );

		// ポケモンの座標
		vec.x = poke_x - ufo->PosX;
		vec.y = poke_y - ufo_y;

		vec.x *= FX32_ONE;
		vec.y *= FX32_ONE;

		//方向ベクトルの長さを取得
		len = VEC_Mag(&vec);

		r1 = PokeAct_GetHitRange(pCPoke->PokeActPtr);
		r2 = UFO_HIT_CIRCLE;
		range = (r1+r2)*FX32_ONE;

//		HOSAKA_PRINT("[%d]poke{%d,%d} ufo{%d,%d} \n",i, poke_x, poke_y, ufo->PosX, ufo_y );

		if (len <= range){
			// データセット
			outPoke->NetID = i / ENTRY_MAX;
			outPoke->PokeID = i % ENTRY_MAX;
			outPoke->pos.X = poke_x;
			outPoke->pos.Y = poke_y;
			return TRUE;	///< 同時キャッチは親優先で誤魔化す
		}
	}

	return FALSE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	境界エリアでどちらに属しているか判定
 *
 *	@param	POS_DATA*		現在の座標
 *	@param	s16 abuttalsY	境界のY座標(↓基準)
 *
 *	@retval	TRUE : 奥のエリア
 */
//-----------------------------------------------------------------------------
static BOOL CheckHitAreaAbuttals( POS_DATA* pos, s16 abuttalsY )
{
	return( ( pos->Y == abuttalsY-1 && ( pos->X < 8 || pos->X > 23 ) ) ||
			( pos->Y == abuttalsY-2 && ( pos->X < 5 || pos->X > 26 ) ) ||
			( pos->Y == abuttalsY-3 && ( pos->X < 2 || pos->X > 29 ) ) );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO スコア処理
 *
 *	@param	UFO_DATA* ufo
 *	@param	TeamDataHead
 *	@param	getPoke
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_SetScore( UFO_DATA* ufo, TEAM_DATA* TeamDataHead, UFO_GET_POKE* getPoke )
{
	POS_DATA pos;

	pos.X = getPoke->pos.X / 8;
	pos.Y = getPoke->pos.Y / 8;

	// 座標からポイント算出
	if( pos.Y < 9 )
	{
		ufo->State = UFO_ST_POINT_1;
		if( CheckHitAreaAbuttals( &pos, 9 ) )
		{
			ufo->State = UFO_ST_POINT_2;
		}
	}
	else if( pos.Y < 15 )
	{
		ufo->State = UFO_ST_POINT_2;
		if( CheckHitAreaAbuttals( &pos, 15 ) )
		{
			ufo->State = UFO_ST_POINT_3;
		}
	}
	else if( pos.Y < 20 )
	{
		ufo->State = UFO_ST_POINT_3;
		if( CheckHitAreaAbuttals( &pos, 20 ) )
		{
			ufo->State = UFO_ST_POINT_5;
		}
	}
	else
	{
		ufo->State = UFO_ST_POINT_5;
	}

	// スコア加点
	{
		PKTHLN_PTR work;
		TEAM_DATA* TeamData;
		TeamData = &TeamDataHead[ getPoke->NetID ];
		work = TeamData->CatchPoke[0].work;

		TeamData->Score = MATH_IMin( TeamData->Score + UfoStateToScore( ufo ), 200 );

		// UFOを取得したプレイヤーを記憶
		ufo->GetPlayerID = getPoke->NetID;

		// AP:獲得
		PTFrame_AddActionPoint( work, getPoke->NetID, getPoke->PokeID, ADD_TYPE_GET, 1 );

		HOSAKA_PRINT("[%d]SCORE GET ufo[%d,%d(%d)] state:%d \n", getPoke->NetID, pos.X, pos.Y, ufo->PosY, ufo->State );
	}

}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO 演算
 *
 *	@param	UFO_DATA* ufo
 *	@param	commUfo
 *	@param	TeamDataHead
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_Calc( UFO_DATA* ufo, CATCH_COMM_UFO* commUfo, TEAM_DATA* TeamDataHead )
{
	if( ufo->bAlive == FALSE ){ return; }

	switch( ufo->State )
	{
	case UFO_ST_NORMAL :
		{
			UFO_GET_POKE getPoke;

			// 当たり判定
			if( UFO_CheckHitPoke( ufo, TeamDataHead, &getPoke ) )
			{
				// スコア処理
				UFO_SetScore( ufo, TeamDataHead, &getPoke );
			}
			// 画面外判定
			else if( ufo->PosY >= DISP_RANGE_Y )
			{
				ufo->PosY = 0;
				ufo->State  = UFO_ST_DISPOUT;
			}
			// 移動
			else
			{
#ifdef DEBUG_UFO_HOOK
				if( debug_ufo_move_trg ) { ufo->PosY += ufo->SpeedY; }
				if( sys.trg & PAD_BUTTON_A ) { ufo->PosY += 8; }
				if( sys.trg & PAD_BUTTON_B ) { ufo->PosY += 80; }
				if( sys.cont & PAD_BUTTON_Y ) { ufo->PosY += 80; }
#else
				ufo->PosY += ufo->SpeedY;
#endif
				ufo->PosX = Catch_GetUfoPosX( ufo->PosY, ufo->Vec );
			}
		}
		break;

	case UFO_ST_DISPOUT :
		// 移動
#ifdef DEBUG_UFO_HOOK
		if( debug_ufo_move_trg ) { ufo->PosY += ufo->SpeedY; }
		if( sys.trg & PAD_BUTTON_A ) ufo->PosY += 8;
		if( sys.trg & PAD_BUTTON_B ) ufo->PosY += 80;
		if( sys.cont & PAD_BUTTON_Y ) ufo->PosY += 80;
#else
		ufo->PosY += ufo->SpeedY;
#endif

		// 終了処理
		if( ufo->PosY >= UFO_DISPOUT_DISTANCE )
		{
			UFO_Delete( ufo );
		}
		break;

	case UFO_ST_POINT_1:
	case UFO_ST_POINT_2:
	case UFO_ST_POINT_3:
	case UFO_ST_POINT_5:
		// 終了処理
		if( ++ufo->ScoreTimer >= UFO_SCORE_SYNC )
		{
			UFO_Delete( ufo );
		}
		break;

	default : GF_ASSERT(0);
	}

	// 通信データ更新
	commUfo->PosY = ufo->PosY * 2 / 8;
	commUfo->Vec = ufo->Vec;
	commUfo->State = ufo->State;
	commUfo->GetPlayerID = ufo->GetPlayerID;

#ifdef DEBUG_UFO_HOOK
	if( sys.trg & PAD_BUTTON_DEBUG )
	{
		HOSAKA_PRINT("UFO[%d] Y=%d commY=%d \n",ufo->ID, ufo->PosY, commUfo->PosY );
	}
#endif
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO管理モジュール 初期化
 *
 *	@param	UFO_CNT_DATA* cnt
 *	@param	TEAM_DATA* TeamDataHead
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_CNT_Init( UFO_CNT_DATA* cnt, TEAM_DATA* TeamDataHead )
{
	// チームポインタを結びつける
	cnt->TeamDataHead = TeamDataHead;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFOのレベル算出
 *
 *	@param	u32 GameSec
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static int CalcUfoLevel( u32 GameSec )
{
	int ret, i;

	for(i=0; i<UFO_LEVEL_MAX; i++)
	{
		if( g_UFO_LevelChangeSync[i] <= GameSec )
		{
			return i;
		}
	}

	// エラー
	return -1;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	UFO管理モジュール 次のUFO出現処理(親のみ)
 *
 *	@param	UFO_CNT_DATA* cnt
 *	@param	GameSec
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_CNT_SetNext( UFO_CNT_DATA* cnt, u32 GameSec )
{
	int i;
	int UfoNum = 1;
	u8 SpeedY;

#ifdef PM_DEBUG
	if( DebugPkthlnWk.TimeInfinity == 0 )
#endif
	{
		// レベル算出
		cnt->CreateLevel = CalcUfoLevel( GameSec );
	}

//	HOSAKA_PRINT(" CreateLevel:%d \n" , cnt->CreateLevel );

	// 生成時間
	switch( cnt->CreateLevel )
	{
	case 0:
	case 2:
		cnt->CreateTimer = GAME_FPS * 1;
		break;
	case 1:
	case 3:
		cnt->CreateTimer = 0;
		break;
	}

	// スピード算出
	if( cnt->CreateLevel < 3 )
	{
		SpeedY = 4;
	}
	else
	{
		SpeedY = 4 * ( 1 + (gf_mtRand() % 2) );
	}

	// UFO最大数
	if( cnt->CreateLevel > 0 )
	{
		UfoNum = 2;
	}

	// UFO初期化
	for( i=0; i<UfoNum; i++ )
	{
		if( cnt->UFO[i].bAlive == FALSE )
		{
			UFO_Init( &cnt->UFO[i], SpeedY, i );
			break;
		}
	}
}


//-----------------------------------------------------------------------------
/**
 *	@brief　UFO管理モジュール 計算（親のみ）
 *
 *	@param	UFO_CNT_DATA* cnt
 *	@param	data
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void UFO_CNT_Calc( UFO_CNT_DATA* cnt, COMM_EVENT_COMMON_DATA* data, u32 GameSec )
{
	int i;
	CATCH_COMM_PARENT_PTR parent;

	parent = PKTHLN_CommPack_GetData(&data->SendShareData);

#ifdef DEBUG_UFO_HOOK
	if( sys.trg & PAD_KEY_UP )
	{
		// 方向を指定
		debug_ufo_vec = (debug_ufo_vec+1) % 15;
	}
	else if( sys.trg & PAD_KEY_DOWN )
	{
		//UFOを自動で動かすかどうか
		debug_ufo_move_trg ^= 1;
	}
#endif

	// 生成
	if( cnt->CreateTimer <= 0 )
	{
		UFO_CNT_SetNext( cnt, GameSec );
	}
	else
	{
		cnt->CreateTimer--;
	}

	// UFO処理
	for( i=0; i<UFO_ID_MAX; i++ )
	{
		CATCH_COMM_UFO* commUfo;
		UFO_DATA* serverUfo;

		commUfo = &parent->Ufo[i];
		serverUfo = &cnt->UFO[i];

		UFO_Calc( serverUfo, commUfo, cnt->TeamDataHead );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	通信ビューア 生成
 *
 *	@param	COMM_VIEWER_WORK* wk
 *	@param	cntSub
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void COMM_VIEWER_Init( COMM_VIEWER_WORK* wk, CATS_SYS_PTR csp, CATS_RES_PTR crp, CATCH_SUB_CNT_PTR cntSub )
{
	int i;
	int k;

	wk->cntSub = cntSub;

	// CAPはここで生成

	// drawPoke
	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		wk->drawPoke[i].capSmoke = OBJ_AddCapMain( csp, crp, 0, 0, NANR_catch_obj_main_smoke, PRI_SMOKE );
	}

	// UFO生成
	for( i=0; i<UFO_ID_MAX; i++ )
	{
		UFO_DRAW* drawUfo = &wk->drawUfo[i];

		for( k=0; k<UFO_CAP_NUM; k++ )
		{
			BOOL bLCDMain = ( k == 1 );

			drawUfo->capUFO[k] = OBJ_AddCapCmn( csp, crp, 0, 0, NANR_catch_obj_cmn_ufo, PRI_UFO, bLCDMain );
			drawUfo->capShadow[k] = OBJ_AddCapCmn( csp, crp, 0, 0, NANR_catch_obj_cmn_shade_s, PRI_UFO_SHADOW, bLCDMain );
		}

		drawUfo->capScore = OBJ_AddCapMain( csp, crp, 0, 0, NANR_catch_obj_main_ten1, PRI_UFO_SCORE );
		drawUfo->capEff = OBJ_AddCapMain( csp, crp, 0, 0, NANR_catch_obj_main_catch_eff, PRI_UFO_EFF );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	通信ビューア 描画
 *
 *	@param	UFO_CNT_DATA* cnt
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void COMM_VIEWER_Draw( COMM_VIEWER_WORK* wk, PKTHLN_PTR work )
{
	COMM_EVENT_COMMON_DATA* data;
	CATCH_COMM_PARENT_PTR parent;
	PKTHLN_CATCH_PTR ptr;

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	ptr = PTFrame_GetEventWorkPtr(work);

	UFO_COMM_Draw( wk, parent, work );
	POKE_COMM_Draw( wk, parent, work );

	{
		u8 idx = parent->ScoreHeader;

		// 点数更新を検知
		if( parent->Score != wk->ScorePre[ idx ] )
		{
			// 点数が増えたチームの旗アニメ + 加点(自チームのみ)
			CatchSub_AddScore( wk->cntSub, idx, parent->Score );
		}

		// 前回のスコア保持
		wk->ScorePre[ idx ] = parent->Score;
	}

	// 表示時間更新
	{
		int time = parent->GameSec - 1;
		CatchSub_DispTime( ptr->cntSub, MATH_IMax( 0, MATH_IMax(0,time) ) );
	}

	// ラスト3秒前表示
	PTFrame_DispLastCount( work, parent->GameSec * GAME_FPS );

	// スコア表示
//	HOSAKA_PRINT( "comm Score[%d]=%d \n", parent->ScoreHeader, parent->Score );
}


//-----------------------------------------------------------------------------
/**
 *	@brief	通信ビューア削除
 *
 *	@param	COMM_VIEWER_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void COMM_VIEWER_Exit( COMM_VIEWER_WORK* wk )
{
	int i;

	for( i=0; i<ACT_POKE_MAX; i++ )
	{
		// 煙CAPの開放
		GF_ASSERT( wk->drawPoke[i].capSmoke );
		CATS_ActorPointerDelete_S( wk->drawPoke[i].capSmoke );

		// TCB強制終了
		if( wk->drawPoke[i].wkJumpFailed.tcb )
		{
			TCB_Delete( wk->drawPoke[i].wkJumpFailed.tcb );
		}
	}

	// UFO描画ワークの強制開放
	for( i=0; i<UFO_ID_MAX; i++ )
	{
		int k;
		UFO_DRAW* drawUfo = &wk->drawUfo[i];

		for( k=0; k<UFO_CAP_NUM; k++ )
		{
			CATS_ActorPointerDelete_S( drawUfo->capUFO[k] );
			CATS_ActorPointerDelete_S( drawUfo->capShadow[k] );
		}

		CATS_ActorPointerDelete_S( drawUfo->capScore );
		CATS_ActorPointerDelete_S( drawUfo->capEff );
	}
}


//-----------------------------------------------------------------------------
/**
 *	@brief	BMPWIN作成
 *
 *	@param	PKTHLN_CATCH_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CreateBmpWin( PKTHLN_CATCH_PTR ptr )
{
	enum
	{
		WIN_CGX_BASE = 1,
		WIN_REC_CGX = WIN_CGX_BASE,
	};

	//----------レコードＢＭＰ---------------
	//ＢＮＰウィンドウデータ
	static const BMPWIN_DAT c_RecordBmpData = {
			BG_FRM_M_RSLT, WIN_REC_PX, WIN_REC_PY,
			WIN_REC_SX, WIN_REC_SY, MAIN_FONT_PAL, WIN_REC_CGX
	};

	GF_BGL_BmpWinAddEx( ptr->bgl, &ptr->Win, &c_RecordBmpData );
}